1. 程式人生 > 其它 >SingnalR 從開發到生產部署閉坑指南

SingnalR 從開發到生產部署閉坑指南

前天倒騰了一份[SignalR在react/go技術棧的實踐], 步驟和思路大部分是外圍框架的應用, 今天趁熱打鐵, 給一個我總結的SignalR避坑指南。

1.SignalR 預設協商

不管是.NET客戶端還是JavaScript客戶端,構建連線時都存在一個預設配置:SkipNegotiation=fasle,負負得正就等於要求協商,這個預設配置的完整含義是 建立SignalR連線時,客戶端要求協商傳輸方式

對應產生下圖:

小技巧:如果你確定你的網路環境能穩定的走websocket傳輸, 為了快速建立實時通訊,可跳過協商請求(設定SkipNegotiation=true), 畢竟每次重新整理頁面,react組價都會重新載入,重新協商再傳輸 費時費力。

 const connection = new HubConnectionBuilder()
        .withUrl(process.env.REACT_APP_APIBASEURL+"realtime", {
          skipNegotiation: true,  
          transport: HttpTransportType.WebSockets
        })
        .withAutomaticReconnect()
        .withHubProtocol(new JsonHubProtocol())
        .configureLogging(LogLevel.Information)
        .build();

注意: SkipNegotiation=true,僅限於客戶端的傳輸方式指定為 websocket, 其他方式均會報錯。

2.SignalR 傳輸協商是fetch請求

跟ajax一樣,fetch請求也是瀏覽器指令碼的一種,所以很明顯也會涉及跨域,標準的CORS方案依然對其有效。

http://localhost:9598/realtime/negotiate?negotiateVersion=1
Post請求
有自定義的請求頭 X-Requested-With, X-Signalr-User-Agent

很明顯,這又會觸發預檢Option請求

故你還需要在使用 CORS Middleware時允許這幾個自定義請求頭。

  // 下面是Go github.com/rs/cors package 支援CORS的程式碼
  
	c := cors.New(cors.Options{
		// AllowedOrigins:   []string{"http://localhost:3000","http://rosenbridge.17usoft.com"},
		AllowOriginFunc: func(origin string) bool {
			return true
		},
		AllowedMethods:   []string{"POST", "GET", "OPTIONS", "PUT", "DELETE"},  // 下面要加上signalr傳輸協商要用到的自定義請求頭
		AllowedHeaders:   []string{"Content-Type", "x-requested-with", "x-signalr-user-agent"},
		AllowCredentials: true,
		Debug:            cfg.Log.Debug,
	})

3. websocket也有同源限制

ws://localhost:9598/realtime?id=aoSD_WZhqbRfPyXVTYsHig==

WebSocket也有同源限制,但是標準的CORS對其無效,因為CORS解決是HTTP指令碼請求的跨域問題,WebSocket說到底不算http協議。

瀏覽器依舊會為我們攜帶Origin標頭,所以服務端需要驗證這些標頭,確保只允許來自預期來源的WebSocket。

// 以下是.NET Core 針對websocket同源限制做出的跨域策略

var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");

app.UseWebSockets(webSocketOptions);

btw, 我使用的GO SignalR庫不支援WebSocket跨域, 我提了一個PR, 已經成功合併,興奮,這是我首次向開源專案提MR且獲得通過的專案。

不僅signalr協商請求需要 CORS, 真正傳輸的websocket協議也有跨域一說,我使用了一個庫,沒有做到cors,我提了一個mr,成功合併。

4. 部署生產後,需要nginx支援

按照預設配置,一般會先協商,再使用websocket傳輸。

部署到生產之後,協商後優先使用WebSocket模式, 但是傳輸失敗了, 自動降級為伺服器傳送事件SSE模式,傳輸成功。

瀏覽器開發者工具看不出啥端倪, 使用Fiddler抓包發現 400 狀態碼

網上搜索了一下,可能是生產的nginx不識別websocket標頭。
在nginx配置裡面新增如下配置就可以了

location / {
            proxy_http_version 1.1; 
            proxy_set_header Upgrade $http_upgrade;                
            proxy_set_header Connection "upgrade";    
}

關注本公眾號的5000+筒靴們應該都知道,本號一直不遺餘力的輸出原創技術、職場心得,內容說不上什麼耳目一新、醍醐灌頂,但號主的技能點一直在進化,本次建立了一個[碼甲哥高質量交流群],希望能和童鞋面對面成長(真誠臉圖片)。


本文來自部落格園,作者:{有態度的馬甲},轉載請註明原文連結:https://www.cnblogs.com/JulianHuang/p/15434137.html

歡迎關注我的原創高價值公眾號