WebSocket 代理

要將客戶端和伺服器之間的連線從 HTTP/1.1 轉換為 WebSocket,會使用 HTTP/1.1 中提供的協定切換機制。

然而,這裡有一個細微之處:由於 "Upgrade" 是一個逐跳 (hop-by-hop)標頭,它不會從客戶端傳遞到代理伺服器。對於正向代理,客戶端可以使用 CONNECT 方法來規避此問題。然而,這不適用於反向代理,因為客戶端不知道任何代理伺服器,因此需要在代理伺服器上進行特殊處理。

從 1.3.13 版本開始,nginx 實作了一種特殊的操作模式,如果代理伺服器返回代碼為 101 (Switching Protocols) 的回應,並且客戶端透過請求中的 "Upgrade" 標頭要求進行協定切換,則允許在客戶端和代理伺服器之間建立通道。

如上所述,包括 "Upgrade" 和 "Connection" 在內的逐跳標頭不會從客戶端傳遞到代理伺服器,因此為了使代理伺服器知道客戶端要將協定切換到 WebSocket 的意圖,必須明確傳遞這些標頭。

location /chat/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

一個更複雜的範例,其中傳送到代理伺服器的請求中的 "Connection" 標頭欄位的值取決於客戶端請求標頭中是否存在 "Upgrade" 欄位。

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;
        }
    }

預設情況下,如果代理伺服器在 60 秒內沒有傳輸任何資料,連線將會關閉。可以使用 proxy_read_timeout 指令增加此逾時時間。或者,可以將代理伺服器設定為定期傳送 WebSocket ping 幀,以重設逾時時間並檢查連線是否仍然有效。