Nginx反向代理websocket
示例:
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
...
location /chat/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
也許你也曾遇到為什麼配置ws/wss協議相關的代理時總是不順利?最後一番搜尋發現需要加上面三行,於是二話不講,ctrl+c/ctrl+v 一套帶走,reload一下, 完成了。
那麼這三行到底有什麼特殊本領呢?簡單看看:
proxy_http_version 1.1;
這一行沒啥說的,設定http協議版本1.1, 這個主要是為了下面的兩行做準備。
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
這兩行就是設定兩個請求頭 Upgrade、Connection,這兩個請求頭都是逐跳標頭(只能傳輸一次,不能透傳), 後端ws程式根據這兩個頭攜帶的資訊來判斷是否使用ws協議來通訊。
-
Upgrade
能且只能在http1.1版本中使用, 用來標識協議升級/轉換, 在我們這篇文章的背景下,這個頭資訊一般是: Upgrade: websocket; 表示客戶端希望使用websocket協議通訊, 那麼後端的ws程式取到頭資訊後會返回101狀態碼(協議轉換),此時瀏覽器就會使用當前的TCP連線建立websocket通道。 -
Connection
在本篇文章的背景下, Connection頭資訊取值upgrade, 表示本次請求是一次協議升級(協議轉換)請求, 配合 Upgrade: websocket資訊, 完整表達了這個請求要升級到websocket協議。
為什麼要顯示指定升級頭?
上面提到了反向代理和逐跳標頭,客戶端發起請求時是和反響代理伺服器建立請求, 此時客戶端攜帶的 Upgrade、Connection頭是不會被反向代理伺服器直接轉發到後端服務的(這就是逐跳標頭), 後端服務獲取不到這兩個頭資訊自然也不會主動去切換協議。
因此,需要在反向代理伺服器轉發上游時帶上客戶端原來的請求頭,才可以完成協議的升級或切換。
容易遇到的問題
- 需要注意多層反向代理的場景,都要顯示指定頭資訊才行,否則不得行。
- wss只要在最外層的代理伺服器上配置即可, 內層的代理伺服器使用ws協議互動。