排查Openresty获取不到Host请求头解决过程详解

目录
  • 开篇
  • 服务框架
  • 问题排查
  • 解决方案
  • 填坑
  • 最终方案

开篇

前几天给客户部署服务,把服务都启动完成,准备验证的时候,发现怎么都访问不到服务,但在服务器里面通过curl来访问接口发现服务是通的,于是展开了一场漫长的排查过程。

服务框架

先说一下我们服务的部署框架,用openresty作为反向代理层、docker部署具体的服务。简化的架构图如下。

问题排查

浏览器访问服务,经过openresty转发到具体的服务。我们服务有两个域名,比如叫 a.example.comb.example.com

在发现访问不同时,立刻查看了openresty的日志,发现无论是a域名还是b域名的请求,日志显示全部打到a域名上去了。

再看日志的详细信息发现openresty$host值不是域名而是ip。发现这个后,打开浏览器调试工具,重新刷新页面,发现浏览器的请求是有$host值的。

那是哪一步把$host丢了呢?在我们服务的openresty上一层可能还存在其他的代理层?感觉有这个可能,之前客户说过他们也有几层代理。一般代理都是nginx,难道nginx转发请求到openresty会把host丢了吗?应该不会啊。

找来客户的运维,问他我们服务的上一层有没有代理,他们说有其他代理,然后说,他们用的是Apache做的代理。

嗯?Apache?不好意思,触及到我的知识盲区了,只是听说过,并没有实际的用过。Apache转发请求到openresty会把host丢失吗?这个我也不清楚。

然后问客户运维,还有没有其他代理?他们说还有CDNF5Apache,就这些了。

现在整体的架构清楚了,架构图如下

好吧,代理还挺多,先联系CDN厂商,让他们协助排查下,CDN厂商还挺配合,给查了日志,发现从CDN经过的请求是有host的。

然后,查看F5的日志,经过各种权限申请,终于看到了F5的日志,发现F5的日志也是有host的。

那只剩下Apache了,又经过各种权限申请,查看到了Apache的日志,嗯,找到罪魁祸首了,Apache向后转发的时候,并没有把host的值给带过来。查到这里,我也松了口气,还好不是我们服务的问题,要不然还要受一大顿批评。

既然找到原因了,就让客户运维去排查为什么Apache没有把host给带过来。一个小时过去了,没有任何回应。。。

解决方案

此时,已经凌晨12点了,客户运维还没有消息,咱也不能坐以待毙,想想有没有其他办法。

于是,在服务器上通过tcpdump抓包,看看Apache带过来了什么东西。

通过抓包来看,Apache确实没有把host带过来,但是有个其他的请求头引起了我的注意:X-Forwarded-HostX-Forwarded-Server。这两个请求头居然有域名信息。

既然host没有域名信息,其他两个头存在,那么我是否可以做一个中转把X-Forwarded-Host的域名信息设置给host呢。想了一下,是可以的,我可以再做一个中转本机转发到本机,然后把X-Forwarded-Host的值赋值给host就好了,说干就干。

再添加一个default.conf文件放到openresty的配置目录,内容如下:

server {
    listen 80;
    server_name _;
    location / {
        proxy_pass http://127.0.0.1:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_x_forwarded_host;
    }
    access_log  /data/nginx/logs/default.access.log main;
}

配置好了,重启openresty试一下,果然可以了。大功告成!

此时,已经凌晨1点了,快睁不开眼了,想着终于可以睡觉了。

填坑

刚高兴了没10分钟,客户运维突然我问,你们服务已经对外提供服务了吗,怎么会这么多日志,一会好几个G了。瞬间不困了,赶紧查看原因,打开nginx日志,发现打印了好多127.0.0.1,很不正常。

而且日志打印的很快,怎么看着有点像死循环?难道刚才加的openresty配置有问题?重新看了看3个openresty配置文件:examplea.confexampleb.confdefault.conf,感觉没啥问题呢,又仔细分析了下。

突然又想到,如果是一个C域名呢?

因为只有A域名和B域名的配置,没有其他域名的配置,所以其他域名又会到default.conf里,如此就产生了死循环,既然找到了原因,那就好办了继续改吧。

最终方案

如果我加个if判断,只有A域名和B域名才做转发,其他域名明显不是我的 服务,直接返回200就好了。

server {
    listen 80;
    server_name _;
    location / {
        set $target_domain 0;
        if ($http_x_forwarded_host != 'a.example.com'){
            set $target_domain "${target_domain}1";
        }
        if ($http_x_forwarded_host != 'b.example.com'){
            set $target_domain "${target_domain}2";
        }
        if ($target_domain = "012"){
            return 200;
        }
        proxy_pass http://127.0.0.1:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_x_forwarded_host;
    }
    access_log  /data/nginx/logs/default.access.log main;
}

好了,到此问题终于解决了,更多关于Openresty获取不到Host的资料请关注我们其它相关文章!

(0)

相关推荐

  • OpenResty中正则模式匹配的2种方法详解

    前言 本文介绍 OpenResty 的两种正则模式匹配. 首先需要说明的是,OpenResty 套件中包含了两种语法:一种是主要基于 FFI API 实现的 OpenResty 语法,一种是类原生 Lua 脚本语言的语法. 在本文所介绍的内容中,对应以上两种语法的正则模式匹配分别是 ngx.re.find 和 string.find . 这两种规则起到完全相同的作用:在 subject string 中搜索指定的模式的串,若找到匹配值就返回它的开始位置和结束位置的位数,否则返回两个 nil 空值

  • Openresty服务器使用lua脚本写的Hello World简单实例

    Openresty提供了丰富的接口和变量给Lua,开发者可以充分利用Lua语言特性和这些接口进行高效率开发.万事开头难,但是对于编程来说能写出Hello world就已经算是成功一半了. 1.安装openresty 2.配置nginx 复制代码 代码如下: server {      listen 80;      server_name localhost;        #charset koi8-r;        #access_log logs/host.access.log main

  • Nginx/Openresty中启用http2支持的方法教程

    本文主要给大家介绍了关于Nginx/Openresty启用http2支持的相关内容,在开始介绍之前,我们先来看一看什么是http2. 以下摘自http2的介绍: HTTP/2 源自 SPDY/2 SPDY 系列协议由谷歌开发,于 2009 年公开.它的设计目标是降低 50% 的页面加载时间.当下很多著名的互联网公司,例如百度.淘宝.UPYUN 都在自己的网站或 APP 中采用了 SPDY 系列协议(当前最新版本是 SPDY/3.1),因为它对性能的提升是显而易见的.主流的浏览器(谷歌.火狐.Op

  • 在Debian11上安装Openresty服务(Nginx+Lua)的详细教程

    目录 Debian 更新系统 添加 openresty 仓库 查看安装的版本: 参考链接 OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库.第三方模块以及大多数的依赖项.用于方便地搭建能够处理超高并发.扩展性极高的动态 Web 应用.Web 服务和动态网关. OpenResty 官方 APT 包仓库提供了 deb 包 (适用于 Ubuntu 和 Debian),可以很方便的安装,一起来看下具体的安装步骤吧. Debian 更新系统

  • openresty中使用lua-nginx创建socket实例

    Lua语言太强大了,至少我是这样觉得的.原始的Lua没有Socket功能,需要使用者下载Lua socket组件,require一下才行.而lua-nginx模块自带了socket功能,而且是100%的非阻塞模式,再次感谢作者章亦春. 使用socket功能很简单,只有几个简单的方法即可主要就是有TCP和UDP的区别.(这里只是lua文件,其他请见Hello world 文章) 复制代码 代码如下: local sock = ngx.socket.tcp() local ok,err = sock

  • 排查Openresty获取不到Host请求头解决过程详解

    目录 开篇 服务框架 问题排查 解决方案 填坑 最终方案 开篇 前几天给客户部署服务,把服务都启动完成,准备验证的时候,发现怎么都访问不到服务,但在服务器里面通过curl来访问接口发现服务是通的,于是展开了一场漫长的排查过程. 服务框架 先说一下我们服务的部署框架,用openresty作为反向代理层.docker部署具体的服务.简化的架构图如下. 问题排查 浏览器访问服务,经过openresty转发到具体的服务.我们服务有两个域名,比如叫 a.example.com 和 b.example.co

  • 关于axios配置请求头content-type实例详解

    目录 前言 axios配置请求头content-type方法如下: 补充:axios 根据接口设置不同的content-type 总结 前言 现在网上可能发送Ajax请求有很多种插件,每种用法可能略有差异,大家只需挑选一种自己喜欢的即可.毕竟现在还有很多人使用jQuery,$.ajax用法也是很多了. axios配置请求头content-type方法如下: axios 是Ajax的一个插件,axios虽然是一个插件,但是我们不需要通过Vue.use(axios)来使用,下载完成后,只需在项目中引

  • 一次 Java 内存泄漏的排查解决过程详解

    由来 前些日子小组内安排值班,轮流看顾我们的服务,主要做一些报警邮件处理.Bug 排查.运营 issue 处理的事.工作日还好,无论干什么都要上班的,若是轮到周末,那这一天算是毁了. 不知道是公司网络广了就这样还是网络运维组不给力,网络总有问题,不是这边交换机脱网了就是那边路由器坏了,还偶发地各种超时,而我们灵敏地服务探测服务总能准确地抓住偶现的小问题,给美好的工作加点料.好几次值班组的小伙伴们一起吐槽,商量着怎么避过服务保活机制,偷偷停了探测服务而不让人发现(虽然也并不敢). 前些天我就在周末

  • Java后台判断ajax请求及处理过程详解

    一.问题描述: 当访问一个需要登录的页面时,会有过滤器或者拦截器进行过滤拦截,如果用户没有登录,则跳转到登录页面. 当用户已经登录进入系统后,然后长时间没操作,等到session过期后,再点击一个ajax请求操作时,这时再跳转到登录页面就不合适了,因为这是ajax操作,拦截后跳到页面返回的结果js识别不了. 二.解决方法: 在过滤器或者拦截器上做识别,针对页面跳转请求和ajax请求分别处理. 页面跳转的不再详说,现在说的是ajax请求. 直接贴代码: import java.io.IOExcep

  • Java Web请求与响应实例详解

    Servlet最主要作用就是处理客户端请求并作出回应,为此,针对每次请求,Web容器在调用service()之前都会创建两个对象,分别是HttpServletRequest和HttpServletResponse.其中HttpServletRequest封装HTTP请求消息,HttpServletResponse封装HTTP响应消息.需要注意的是,Web服务器运行过程中,每个Servlet都会只创建一个实例对象,不过每次请求都会调用Servlet实例的service(ServletRequest

  • Vue axios与Go Frame后端框架的Options请求跨域问题详解

    跨域问题可从前后两端分开排查: 前端:Vue + axios axios 请求头使用 'Content-Type': 'application/json', 并且在Header中设置了 Authorization 字段用于传递 Token, 参数未经 Qs 转码, 使用以下代码测试登录接口: // 为方便操作,已将 axios 实例挂载到 this.$axios 上 this.$axios.post('/signin', {account: '', password: ''}) .then(re

  • http proxy 对网络请求进行代理使用详解

    目录 正文 命令行启动服务器 详细的调用栈 捕捉错误 正文 使用下面这段简单的代码对网络请求进行代理: const http = require('http'); const httpProxy = require('http-proxy'); const targetUrl = 'https://www.sap.cn/index.html'; const proxy = httpProxy.createProxyServer({ target: targetUrl, }); http.crea

  • Android 网络请求框架Volley实例详解

    Android 网络请求框架Volley实例详解 首先上效果图 Logcat日志信息on Reponse Volley特别适合数据量不大但是通信频繁的场景,像文件上传下载不适合! 首先第一步 用到的RequetQueue RequestQueue.Java RequestQueue请求队列首先得先说一下,ReuqestQueue是如何对请求进行管理的...RequestQueue是对所有的请求进行保存...然后通过自身的start()方法开启一个CacheDispatcher线程用于缓存调度,开

  • Java编程Post数据请求和接收代码详解

    这两天在做http服务端请求操作,客户端post数据到服务端后,服务端通过request.getParameter()进行请求,无法读取到数据,搜索了一下发现是因为设置为text/plain模式才导致读取不到数据 urlConn.setRequestProperty("Content-Type","text/plain; charset=utf-8"); 若设置为以下方式,则通过request.getParameter()可以读取到数据 urlConn.setReq

  • linux下cpu飙高原因排查过程详解

    目录 前言 开始 步骤 排查 前言 cpu飙高是很常见的线上问题,这都不会的话,属实有点拉跨 兄弟萌不用慌,来我教你一套连招 开始 先来个项目,整个api,到时候我们请求/cpu/{count}就能手动拉高cpu,机智鬼~ @GetMapping("/cpu/{count}") public long cpuTest(@PathVariable("count") long count) { long number = 0; for (int i = 0; i <

随机推荐