阿里雲負載不支持 WebSocket 協議與 WSS 和 Nginx 配置問題


WebSocket 是 HTML5 下一種新的協議。它實現了瀏覽器與服務器全雙工通信,能更好的節省服務器資源和帶寬並達到實時通訊的目的。它與HTTP一樣通過已建立的TCP連接來傳輸數據,但是它和HTTP最大不同是:

  • WebSocket是一種雙向通信協議。在建立連接后,WebSocket服務器端和客戶端都能主動向對方發送或接收數據,就像Socket一樣;
  • WebSocket需要像TCP一樣,先建立連接,連接成功后才能相互通信。

WebSocket 連接本質上是一個 TCP 連接,比較輪詢在數據傳輸的穩定性和數據傳輸量的大小方面,具有很大的性能優勢。

瀏覽器請求

GET / HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: example.com Origin: null Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ== Sec-WebSocket-Version: 13

客戶端發起的WebSocket連接報文類似傳統HTTP報文,Upgrade:websocket參數值表明這是WebSocket類型請求,Sec-WebSocket-Key是WebSocket客戶端發送的一個 base64編碼的密文,要求服務端必須返回一個對應加密的Sec-WebSocket-Accept應答,否則客戶端會拋出Error during WebSocket handshake錯誤,並關閉連接。

在請求中的Sec-WebSocket-Key是隨機的,服務器端會用這些數據來構造出一個SHA-1的信息摘要。把Sec-WebSocket-Key加上一個魔幻字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11。使用 SHA-1 加密,之后進行 BASE-64編碼,將結果作為 Sec-WebSocket-Accept 頭的值,返回給客戶端;WebSocket 先是通過 HTTP 建立連接, 然后通過 101 狀態碼, 表示切換協議,在配置里是 Upgrade。

服務器回應

HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= Sec-WebSocket-Origin: null Sec-WebSocket-Location: ws://example.com/

Sec-WebSocket-Accept 的值是服務端采用與客戶端一致的密鑰計算出來后返回客戶端的,HTTP/1.1 101 Switching Protocols表示服務端接受WebSocket協議的客戶端連接,經過這樣的請求-響應處理后,兩端的WebSocket連接握手成功, 后續就可以進行TCP通訊了。用戶可以查閱WebSocket協議棧了解WebSocket客戶端和服務端更詳細的交互數據格式。

瀏覽器兼容性

最新的主流瀏覽器對WebSocket支持良好:

  • Chrome 4+
  • Firefox 4+
  • Internet Explorer 10+
  • Opera 10+
  • Safari 5+

我們在阿里雲啟用全站 HTTPS 后,我們發現阿里雲 webscoket 通信報錯 400 Bad Request 錯誤,開始以為是啟用HTTPS的問題,后面發現阿里雲的負載均衡(LB)根本就不支持 ws 協議(https://help.aliyun.com/document_detail/63421.html?spm=5176.doc63420.6.714.hC3lA2),Google 了一番,決定使用 nginx 代理。

備注:阿里 ws 與 http2 支持情況 https://yq.aliyun.com/articles/277584?spm=5176.10695662.1996646101.searchclickresult.2a8d761c2PJag1

Request URL:wss://singalr.xxx.cn/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=xmpmOB19Q6d7X32GFEP7lTFm7DPSJIcRALZOxbASrpogN5MPTTBafipQsNBs0x5J7wvUm5QI8e1iViqETc9Q8%2FGHCLZo5GhJsXYRWmOzsICh5LDyQDGnAsRSC3GvBMsQ&connectionData=%5B%7B%22name%22%3A%22signalrpushhub%22%7D%5D&tid=9
Request Method:GET
Status Code:400 Bad Request

Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:https://xxx.cn
Cache-Control:no-cache
Connection:keep-alive
Content-Type:text/html
Date:Wed, 17 May 2017 02:09:56 GMT
Expires:-1
Pragma:no-cache
Transfer-Encoding:chunked
X-AspNet-Version:4.0.30319
X-Content-Type-Options:nosniff
X-Powered-By:ASP.NET

Response Headers
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:no-cache
Connection:Upgrade
Cookie:_pms_session=5d0gqrezzfgvivj2b4oaecy3; acw_tc=AQAAAMvoFF/VeQoAJkNKfD0idg5CQvGL
Host:singalr.xxx.cn
Origin:https://p2.xxx.cn
Pragma:no-cache
Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key:V2NZvyJw/CJtAdn68xDZWA==
Sec-WebSocket-Version:13
Upgrade:websocket
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36

Query String Parameters
transport:webSockets
clientProtocol:1.5
connectionToken:xmpmOB19Q6d7X32GFEP7lTFm7DPSJIcRALZOxbASrpogN5MPTTBafipQsNBs0x5J7wvUm5QI8e1iViqETc9Q8/GHCLZo5GhJsXYRWmOzsICh5LDyQDGnAsRSC3GvBMsQ
connectionData:[{"name":"signalrpushhub"}]
tid:9

WebSocket 的 Nginx 配置

 開始以為是 HTTPS 443 監聽的問題,后面修發現HTTP下ws協議也不可以,咨詢了一番,最后發現是阿里雲負載均衡不支持 ws 協議的問題。單獨把 signalr 的服務端使用 nginx 代理負載 ,其他服務器還是使用阿里雲的負載

upstream singalr { 
   server 192.168.1.5;
   server 192.168.1.4; 
}

server {
    listen       443 ssl;
    server_name  singalr.com; 
    #charset koi8-r; 
    #access_log logs/host.access.log main;

    ssl on;
    ssl_certificate /etc/ssl/private/xxxx.pem;
    ssl_certificate_key /etc/ssl/private/xxx.key;
    
    location / { 
        proxy_pass http://singalr;
        proxy_redirect    off;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

REFER:
http://nginx.org/en/docs/http/websocket.html
https://socket.io/
https://github.com/SignalR/SignalR
https://github.com/aspnet/SignalR
http://blog.mixu.net/2011/08/13/nginx-websockets-ssl-and-socket-io-deployment/
https://docs.microsoft.com/en-us/aspnet/signalr/overview/performance/scaleout-with-redis
http://www.ruanyifeng.com/blog/2017/05/websocket.html
WebSocket 實現原理
http://zeeyang.com/2017/07/02/websocket/
https://www.qcloud.com/document/product/214/4150
https://www.zhihu.com/question/20215561


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM