首頁 > 軟體

排查Openresty獲取不到Host請求頭解決過程詳解

2022-12-01 14:02:31

開篇

前幾天給客戶部署服務,把服務都啟動完成,準備驗證的時候,發現怎麼都存取不到服務,但在伺服器裡面通過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的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com