排查Openresty获取不到Host请求头解决过程详解
目录
- 开篇
- 服务框架
- 问题排查
- 解决方案
- 填坑
- 最终方案
开篇
前几天给客户部署服务,把服务都启动完成,准备验证的时候,发现怎么都访问不到服务,但在服务器里面通过curl
来访问接口发现服务是通的,于是展开了一场漫长的排查过程。
服务框架
先说一下我们服务的部署框架,用openresty
作为反向代理层、docker
部署具体的服务。简化的架构图如下。
问题排查
浏览器访问服务,经过openresty
转发到具体的服务。我们服务有两个域名,比如叫 a.example.com
和 b.example.com
。
在发现访问不同时,立刻查看了openresty
的日志,发现无论是a域名
还是b域名
的请求,日志显示全部打到a域名
上去了。
再看日志的详细信息发现openresty
的$host
值不是域名而是ip。发现这个后,打开浏览器调试工具,重新刷新页面,发现浏览器的请求是有$host
值的。
那是哪一步把$host
丢了呢?在我们服务的openresty
上一层可能还存在其他的代理层?感觉有这个可能,之前客户说过他们也有几层代理。一般代理都是nginx
,难道nginx
转发请求到openresty
会把host
丢了吗?应该不会啊。
找来客户的运维,问他我们服务的上一层有没有代理,他们说有其他代理,然后说,他们用的是Apache
做的代理。
嗯?Apache
?不好意思,触及到我的知识盲区了,只是听说过,并没有实际的用过。Apache
转发请求到openresty
会把host
丢失吗?这个我也不清楚。
然后问客户运维,还有没有其他代理?他们说还有CDN
、F5
、Apache
,就这些了。
现在整体的架构清楚了,架构图如下
好吧,代理还挺多,先联系CDN
厂商,让他们协助排查下,CDN
厂商还挺配合,给查了日志,发现从CDN
经过的请求是有host
的。
然后,查看F5
的日志,经过各种权限申请,终于看到了F5
的日志,发现F5
的日志也是有host
的。
那只剩下Apache
了,又经过各种权限申请,查看到了Apache
的日志,嗯,找到罪魁祸首了,Apache
向后转发的时候,并没有把host
的值给带过来。查到这里,我也松了口气,还好不是我们服务的问题,要不然还要受一大顿批评。
既然找到原因了,就让客户运维去排查为什么Apache
没有把host
给带过来。一个小时过去了,没有任何回应。。。
解决方案
此时,已经凌晨12点了,客户运维还没有消息,咱也不能坐以待毙,想想有没有其他办法。
于是,在服务器上通过tcpdump
抓包,看看Apache
带过来了什么东西。
通过抓包来看,Apache
确实没有把host
带过来,但是有个其他的请求头引起了我的注意:X-Forwarded-Host
、X-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.conf
、exampleb.conf
、default.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的资料请关注我们其它相关文章!