排查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的資料請關注其它相關文章!