前天倒腾了一份[SignalR在react/go技术栈的实践], 步骤和思路大部分是外围框架的应用, 今天趁热打铁, 给一个我总结的SignalR避坑指南。
1.SignalR 默认协商
不管是.NET客户端还是JavaScript客户端,构建连接时都存在一个默认配置:SkipNegotiation=fasle
,负负得正就等于要求协商,这个默认配置的完整含义是 建立SignalR连接时,客户端要求协商传输方式。
对应产生下图:
小技巧:如果你确定你的网络环境能稳定的走websocket传输
, 为了快速建立实时通信,可跳过协商请求(设置SkipNegotiation=true
), 毕竟每次刷新页面,react组价都会重新加载,重新协商再传输 费时费力。
1 | php复制代码 const connection = new HubConnectionBuilder() |
注意: 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时允许这几个自定义请求头。
1 | php复制代码 // 下面是Go github.com/rs/cors package 支持CORS的代码 |
ws://localhost:9598/realtime?id=aoSD_WZhqbRfPyXVTYsHig==
WebSocket
也有同源限制,但是标准的CORS对其无效,因为CORS解决是HTTP脚本请求的跨域问题,WebSocket说到底不算http协议。
浏览器依旧会为我们携带Origin
标头,所以服务端需要验证这些标头,确保只允许来自预期来源的WebSocket。
1 | ini复制代码// 以下是.NET Core 针对websocket同源限制做出的跨域策略 |
btw, 我使用的GO SignalR库不支持WebSocket跨域, 我提了一个PR, 已经成功合并,兴奋,这是我首次向开源项目提MR且获得通过的项目。
- 部署生产后,需要nginx支持
按照默认配置,一般会先协商,再使用websocket传输。
部署到生产之后,协商后优先使用WebSocket模式
, 但是传输失败了, 自动降级为服务器发送事件SSE
模式,传输成功。
浏览器开发者工具看不出啥端倪, 使用Fiddler抓包发现 400 状态码
网上搜索了一下,可能是生产的nginx不识别websocket标头。
在nginx配置里面添加如下配置就可以了
1 | ini复制代码location / { |
以上是马甲哥整理的SignalR从开发到部署的闭坑指南,因为微信公众号内容发布后不方便重新编辑,后续有更多闭坑技能,会同步到这里。
本文转载自: 掘金