WebSocket 和HTTP雖然是不同協定,但是兩者「握手」方式相容。通過HTTP升級機制,使用HTTP的Upgrade和Connection協定頭的方式可以將連線從HTTP升級為WebSocket。
Websocket 使用 ws 或 wss 的統一資源標誌符,類似於 HTTPS,其中 wss 表示在 TLS 之上的 Websocket。如:
ws://example.com/wsapi
wss://secure.example.com/
Websocket 使用和 HTTP 相同的 TCP 埠,可以繞過大多數防火牆的限制。預設情況下,Websocket 協定使用 80 埠;執行在 TLS 之上時,預設使用 443 埠。
一個典型的Websocket握手請求如下:
使用者端請求:
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13
伺服器迴應:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/
關鍵點:
知識點參考:《HTML5 WebSocket》
1、wss協定實際是websocket +SSL,就是在websocket協定上加入SSL層,類似https(http+SSL)。
2、利用nginx代理wss【通訊原理及流程】
server {
listen 80;
server_name 域名;
proxy_http_version 1.1;
……
#啟用支援websocket連線的設定
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
location / {
proxy_redirect off;
proxy_pass http://myweb_backend;
proxy_connect_timeout 60;
proxy_read_timeout 600;
proxy_send_timeout 600;
}
}
重要的是這兩行,它表明是websocket連線進入的時候,進行一個連線升級將http連線變成websocket的連線。
啟用支援websocket連線:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy read timeout 表明連線成功以後等待伺服器響應的時候,如果不設定預設為60s;
proxy_http_version 1.1;表明使用http版本為1.1
上面的設定將websocket寫到某個server裡了。實際專案上nginx代理的可能是多個站點,多個服務,這就需要統一設定一下。另外對於低版本nginx的設定不支援"upgrade"引數的情況下可以這樣寫:
首先在nginx的全域性塊(一般是http塊)裡面加上websocket的引數對映
http {
include mime.types;
default_type text/html;
charset utf-8;
log_format proxy '$http_x_real_ip - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" $request_time $upstream_response_time';
access_log /dev/stdout proxy;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75;
keepalive_requests 1000;
client_max_body_size 1020000M;
client_body_buffer_size 256k;
large_client_header_buffers 4 128k;
client_header_buffer_size 32k;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;
#注意,必須加下面這段websocket的引數對映
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
include /etc/nginx/conf.d/*.conf;
}
這裡重要的是這四行:
注意,必須加下面這段websocket的引數對映
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
然後在你的server或者location塊裡面加上這兩行即可:
server {
listen 80;
server_name 域名;
proxy_http_version 1.1;
……
#注意,必須加下面這段websocket的設定
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
location / {
proxy_redirect off;
proxy_pass http://myweb_backend;
proxy_connect_timeout 60;
proxy_read_timeout 600;
proxy_send_timeout 600;
}
}
注意:因為websocket是長連線,請求過程不關閉的所以一般連線狀態碼是101(請求者已要求伺服器切換協定,伺服器已確認並準備切換。)
CloseEvent介面的程式碼唯讀屬性返回WebSocket連線關閉程式碼,指示伺服器關閉連線的原因。
值:一個整數的WebSocket連線關閉範圍為1000-4999的程式碼,指示伺服器關閉連線的原因。
websocket連線關閉狀態碼:
https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
網頁控制檯報錯現象:
1)現象一:網頁控制檯報"WebSocket connection to 'ws://' failed:<無報錯資訊>"
2)現象二:網頁控制檯報"WebSocket connection to 'ws://' failed:Error during WebSocket handshake: Unexpected response code: 400"
3)現象三:網頁控制檯報"WebSocket connection to 'ws://' failed:The request timed out.
問題原因與處理方法:
1.代理/防火牆對存取埠只開通了http協定,未支援websocket協定。可以將代理/防火牆的7層轉發改為4層轉發,確認是否為websocket協定/長連線的支援問題。
2.代理nginx未支援websocket協定轉發,檢查nginx組態檔中的Upgrade和Connection設定。
【完】