Nginx的WebSocket反向代理實踐過程
一、HTTP 協(xié)議升級機制回顧
- Upgrade/Connection 報頭
客戶端發(fā)起 WebSocket 握手時,會在普通 HTTP 請求中加入
Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: <隨機值> Sec-WebSocket-Version: 13
服務(wù)端若接受協(xié)議切換,會以 101 Switching Protocols
響應(yīng),并同樣返回 Upgrade
和 Connection
報頭。
- Hop-by-Hop 報頭限制
HTTP/1.1 中,Upgrade
與 Connection
都屬于 Hop-by-Hop 報頭,只能在相鄰節(jié)點間生效,不會被普通反向代理轉(zhuǎn)發(fā)。因此,需要在 Nginx 明確地把這兩者從客戶端請求里取出,并再設(shè)置到轉(zhuǎn)發(fā)給后端的請求頭中。
二、Nginx 代理 WebSocket 的關(guān)鍵配置
1. 基本示例
location /chat/ { # 將請求轉(zhuǎn)發(fā)到后端 WebSocket 服務(wù) proxy_pass http://backend; # 使用 HTTP/1.1 協(xié)議,以支持 Upgrade proxy_http_version 1.1; # 將客戶端請求中的 Upgrade 與 Connection 頭轉(zhuǎn)發(fā)給后端 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
proxy_http_version 1.1
強制使用 HTTP/1.1,否則默認(rèn)的 HTTP/1.0 無法支持協(xié)議升級。
proxy_set_header Upgrade $http_upgrade
將客戶端傳來的 Upgrade: websocket
透傳給后端。
proxy_set_header Connection “upgrade”
明確指定與 Upgrade
配合使用。
2. 智能化 Connection 設(shè)置
在某些場景下,希望僅在真有升級需求時才發(fā) "upgrade"
,否則保持連接關(guān)閉。
可借助 Nginx 的 map
模塊:
# 將是否存在 Upgrade 頭映射成變量 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; } }
- 如果客戶端請求里沒有
Upgrade
,則向后端發(fā)送Connection: close
,更符合一般 HTTP 請求的語義。
三、超時與心跳優(yōu)化
默認(rèn)情況下,Nginx 在代理 WebSocket 連接時,如果后端在 60 秒內(nèi)沒有任何數(shù)據(jù)回傳,會主動關(guān)閉連接。
這對于長時間空閑但后續(xù)可能仍要推送消息的場景并不友好。
常用的優(yōu)化方案有兩種:
1.延長 Nginx 的 proxy_read_timeout
在 location
或 http
、server
級別添加:
proxy_read_timeout 3600s; # 將超時時間提升到 1 小時
2.后端發(fā)送 WebSocket Ping
讓后端應(yīng)用周期性地向客戶端(經(jīng)過 Nginx)發(fā)送 Ping 幀,觸發(fā) Nginx 讀取數(shù)據(jù),從而重置超時計時器,同時還能檢測連接健康狀態(tài)。
四、完整示例
http { map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream backend { server 127.0.0.1:8080; # 后端 WebSocket 服務(wù)地址 # 可根據(jù)實際情況添加多臺服務(wù)器,實現(xiàn)負(fù)載均衡 } server { listen 80; server_name example.com; # 靜態(tài)資源處理(可選) location /static/ { root /var/www/html; } # WebSocket 代理入口 location /chat/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # 轉(zhuǎn)發(fā)客戶端真實 IP(可選) proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 超時配置 proxy_read_timeout 3600s; proxy_send_timeout 3600s; } } }
五、實踐要點與注意事項
- HTTPS + WSS
若在前端使用 wss://
(即 TLS 加密的 WebSocket),必須在 Nginx 上配置對應(yīng)的 SSL 證書,并在 server
塊中使用 ssl_certificate
、ssl_certificate_key
等指令。
- 負(fù)載均衡與 Sticky Session
對于需要在多實例間保持會話一致性的業(yè)務(wù),可考慮基于 Cookie 或 IP 哈希的 Sticky Session 配置,或者將業(yè)務(wù)設(shè)計成無狀態(tài)。
- 安全加固
可以在 Nginx 中加入 limit_conn
、limit_req
等限流指令,防止惡意連接耗盡資源;也可結(jié)合 lua-nginx-module
實現(xiàn)更復(fù)雜的鑒權(quán)或動態(tài)路由。
總結(jié)
通過上述方式,Nginx 能夠高效、穩(wěn)定地將客戶端的 HTTP 升級請求(Upgrade)轉(zhuǎn)發(fā)到后端 WebSocket 服務(wù),實現(xiàn)反向代理與負(fù)載均衡。
在此基礎(chǔ)上,再配合合理的超時調(diào)整、心跳檢測與安全限流,即可構(gòu)建面向生產(chǎn)環(huán)境的高可用、可擴展的實時通信平臺。
希望本文能幫助你快速上手 Nginx WebSocket 代理,并打造符合業(yè)務(wù)需求的實時架構(gòu)。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
nginx將https協(xié)議反向代理到http協(xié)議請求上的實現(xiàn)
本文主要介紹了nginx將https協(xié)議反向代理到http協(xié)議請求上的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-10-10Nginx配置缺少導(dǎo)致CSS不起作用的問題及解決方法
在Web開發(fā)中,確保樣式表正確加載是前端顯示正常工作的關(guān)鍵,然而,有時候即使CSS文件的路徑和代碼本身沒有問題,CSS樣式也可能無法正確應(yīng)用,本文將分享一個常見的問題——Nginx配置缺少導(dǎo)致的CSS不起作用,以及如何解決這個問題,感興趣的朋友一起看看吧2024-07-07nginx中g(shù)zip_types匹配content-type的方式
這篇文章主要介紹了nginx中g(shù)zip_types匹配content-type的方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05