1. 程式人生 > >一次 Nginx proxy_set_header 故障問題解析和延升

一次 Nginx proxy_set_header 故障問題解析和延升

[toc] 本文會先由一個問題引入,然後再進行多種情況進行分析。 ## 一、問題和排查步驟 #### 1.1 問題基本資訊 ​ 我們應用程式從程式碼層面收到的 Header 中的 Host 的值是 `upstream` 的 名稱。 我們程式是需要獲取到實際的值。所以這裡存在一個問題。 我們先看看我們的 `nginx` 配置。 ```nginx upstream open-hz8443{ server 10.60.6.184:8000 max_fails=1 fail_timeout=3s weight=10; } server{ server_name 192.168.80.132; listen 80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 3s; proxy_read_timeout 120s; proxy_send_timeout 120s; proxy_next_upstream error timeout invalid_header http_404 http_502 http_504 http_500; location / { proxy_pass http://open-hz8443; } location ^~ /wss/v1 { proxy_pass http://open-hz8443; proxy_set_header Connection "upgrade"; proxy_set_header Upgrade $http_upgrade; tcp_nodelay on; } } ``` 我們請求 `http://192.168.80.132/wss/v1`, 我們可以在後端(`10.60.6.184:8000`)獲取到 Host 的值為 `open-hz8443`。 這個是我們做了一個 指令碼,用於獲取請求的所有的資料的。 指令碼具體內容在文末。 ``` Connection: upgrade Host: open-hz8443 # 獲取到的Host 是 open-hz8443 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 FS Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 10.210.20.43 - - [04/Jan/2021 15:54:46] "GET /wss/v1 HTTP/1.0" 200 - ``` ### 1.2 問題解析 首先這裡有知識點: 1. 我們在 Server 配了 `proxy_set_header Host $host;` , 我們在 location 是隻配置了 ``` proxy_set_header Connection "upgrade"; proxy_set_header Upgrade $http_upgrade; ``` 我們的 Host 最初我認為是會繼承 Server 配置的 `proxy_set_header Host $host; ` , 但是明顯是沒有繼承的,而是直接拿的 `upstream` 的名稱。說明沒有繼承,那麼這裡是有一個什麼規則? 我們往下看。 2. 查詢 `Nginx` 官方文件。 >http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header ``` Allows redefining or appending fields to the request header passed to the proxied server. The value can contain text, variables, and their combinations. These directives are inherited from the previous configuration level if and only if there are no proxy_set_header directives defined on the current level. By default, only two fields are redefined: ``` 大概意思就是當我們沒有設定 `proxy_set_header` 才會從上一層級繼承,當我們設定了 `proxy_set_header` ,也就意味著我們不從上面 server 的 `proxy_set_header Host $host; ` 進行繼承。 那為什麼會顯示 ` open-hz8443 `, 是因為有一個預設值 ``` proxy_set_header Host $proxy_host; ``` 這個 `proxy_host`, - 當我們設定了 `upstream` 的話,也就是上面的例子`$proxy_host` 就是 upstream的名稱值. - 當我們直接使用的 ` proxy_pass http://10.60.6.184:8000` 的話,那麼 `$proxy_host` 表示的就是 `10.60.6.184:8000` ### 1.3、解決辦法 在 `location ^~ /wss/v1` 下面增加配置 ` proxy_set_header Host $host;`。 ``` location ^~ /wss/v1 { proxy_pass http://open-hz8443; proxy_set_header Host $host; proxy_set_header Connection "upgrade"; proxy_set_header Upgrade $http_upgrade; tcp_nodelay on; } ``` ## 二、擴充套件-各種情況對比 #### 預設兩項 ``` proxy_set_header Host $proxy_host; proxy_set_header Connection close; ``` #### proxy_set_header 其他項等 ``` proxy_set_header Connection "upgrade"; proxy_set_header Upgrade $http_upgrade; ``` | Server 設定 proxy_set_header 其他項 | Server 設定 proxy_set_header 預設兩項 | location 設定 proxy_set_header 預設兩項 | location 設定 proxy_set_header 其他項 | 預設值生效 | 預設值不生效 | | ----------------------------------- | ------------------------------------- | --------------------------------------- | ------------------------------------- | --------------- | --------------- | | 1 | 1 | 1 | 1 | | 1 繼承location | | 1 | 1 | 0 | 1 | 1(不繼承Server) | | | 1 | 1 | 1 | 0 | | 1 繼承location | | 1 | 1 | 0 | 0 | | 1 繼承server | | 1 | 0 | 1 | 0 | | 1 繼承location | | 1 | 0 | 0 | 0 | 1 預設 | | | 1 | 0 | 0 | 11 | 1 預設 | | | 1 | 0 | 1 | 1 | | 1 繼承location | | 0 | 1 | 0 | 0 | | 1 繼承server | | 0 | 1 | 0 | 1 | 1 預設 | | | 0 | 1 | 1 | 0 | | 1 繼承location | | 0 | 1 | 1 | 1 | | 1 繼承location | | 0 | 0 | 0 | 1 | 1 預設 | | | 0 | 0 | 1 | 0 | | 1 繼承location | | 0 | 0 | 1 | 1 | | 1 繼承location | | 0 | 0 | 0 | 0 | 1 預設 | | ### 總結 1. location 設定了 proxy_set_header 就不繼承,但繼承預設值,預設值優先順序低於 location設定。 2. location 未設定了proxy_set_header ,就往上繼承,直到預設值。 只要呼叫了 proxy_set_header,並沒有設定 host 和 connection ,預設重寫host、connection兩個頭。 ## 三、擴充套件 ->指令碼 ### proxy_set_header $host $proxy_host $http_host 各個變數含義 [記錄一次 Nginx 配置 proxy_pass 後 返回404問題](https://www.cnblogs.com/operationhome/p/14232793.html#%E4%BA%8C%E3%80%81%E6%89%A9%E5%B1%95--%E5%B8%B8%E7%94%A8%E7%9A%84%E9%85%8D%E7%BD%AE) ### python 獲取請求所有資料資訊指令碼 ```python #!/usr/bin/env python import SimpleHTTPServer import SocketServer PORT = 8000 class GetHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_GET(self): print(self.headers) self.send_response(200, "") def do_POST(self): print(self.headers) content_length = self.headers.getheaders('content-length') length = int(content_length[0]) if content_length else 0 print(self.rfile.read(length)) self.send_response(200, "") Handler = GetHandler httpd = SocketServer.TCPServer(("", PORT), Handler) httpd.serve_foreve