今天SignalR部署在測試環境伺服器前端出現無法連線,前端報錯如下:
failed: Error during WebSocket handshake: Unexpected response code: 200
Failed to start the transport 'WebSockets': null
SignalR地址直接報錯404
然後檢視伺服器端是否有什麼問題,伺服器端也有報錯如下
Microsoft.AspNetCore.SignalR.HubConnectionContext - Failed connection handshake.
看前端報錯看像是WebSocket問題,因為SignalR本質還是通過WebSocket來實現通訊的,根據錯誤像是伺服器不支援WebSocket,我們是使用的Nginx做代理的時候預設配置不支援WebSocket。需要修改代理設定,需要改代理請求頭的設定。
主要修改如下,在location節點下面新增。
文末有完整的nginx配置例項可複製。
proxy_http_version 1.1
指定使用http版本,因為只有http1.1才支援長連線。
proxy_set_header Upgrade $http_upgrade
將客戶端http請求頭Upgrade 透傳過來
roxy_set_header Connection “upgrade”
upgrade意思是告訴伺服器使用最高版本協議進行通訊。
預設roxy_set_header Connection這裡如果不寫的話,在htt1.0中Connection 預設是close的,即連線請求完畢後就關閉。
以上歸根到底都是基於http頭進行設定修改,如果我們自己本身對http頭有更多瞭解,還是有很大幫助的。
按照這個修改,然後重啟Nginx。nginx –s reload。
再看前端signal發現連線成功
但是這個時候其他webapi介面無法請求了,swagger可以開啟但是介面無法請求了報400
這個時候也想到了應該是Nginx問題,畢竟再沒有修改Nginx的時候其他介面是可以使用的。當然如果SignalR和api業務伺服器本來就是相互獨立那麼就不會存在這個情況,我的SignalR和業務服務介面都是在一起的。
原因就在於我們剛剛配置了Nginx代理時使用長連線,但是我們webapi其他介面都是短連線的。所以我們要將signal的連線代理和webapi其他介面的代理分開。
最後的設定如下
location 就是Nginx的路由匹配,這樣新增後當我們請求url域名後面是SignalR則使用長連線進行代理轉發了。location通常我們還回用於靜態檔案的代理,這樣靜態檔案直接通過nginx就能返回到前端了。不需要請求到後端伺服器。
本次完整的nginx配置如下
server{ listen 80; listen 443 ssl; #域名 server_name t-aabb.com; #https配置證書和ssl ssl_certificate cert/_.aabb.com.crt; ssl_certificate_key cert/_.aabb.com.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; client_max_body_size 100m; #後端服務代理 location / { proxy_pass http://192.168.0.28:8080; proxy_set_header Host $http_host; } #Signal代理 location /SignalR { proxy_pass http://192.168.0.28:8080; #啟用http長連線支援websocket proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }