内容提要
SignalR是ASP.NET Core的实时通信库,支持服务器向客户端推送消息,自动协商WebSocket、SSE或长轮询传输。核心是Hub类,支持分组、强类型调用、流式传输、身份验证及Redis或Azure SignalR Service横向扩展。适用于聊天、通知、仪表板等场景,相比原生WebSocket更简单,但内部服务间通信建议用gRPC。
延伸解读
传输降级机制的实际意义
SignalR 自动协商传输协议,优先 WebSocket,降级到 SSE 或长轮询。这意味着在老旧浏览器或受限网络环境下,应用仍能保持实时功能,无需开发者手动处理降级逻辑。但需注意,降级到长轮询会增加延迟和服务器负载,因此应尽量确保 WebSocket 可用。
分组与重连的注意事项
SignalR 的分组由服务器管理,但连接断开重连后分组不会自动恢复,需要应用在 OnConnectedAsync 中基于用户或业务逻辑重新加入分组。此外,重连后 ConnectionId 会变化,若依赖 ConnectionId 定向发送,需更新映射关系。
横向扩展的两种方案对比
自托管多实例时,需使用 Redis Backplane 同步消息,但会引入运维复杂性,如粘性会话问题。Azure SignalR Service 作为托管方案,客户端直接连接服务,应用服务器仅发布消息,消除了 Backplane 和粘性会话的顾虑,但需评估云服务成本与依赖。
选型建议:SignalR 与 gRPC 的边界
SignalR 适合面向浏览器的实时功能,如聊天、通知、仪表板,内置降级和重连。但内部服务间双向流通信,gRPC 更合适,因其基于 HTTP/2,性能更高且强类型。若需完全控制协议,可选原生 WebSocket,但需自行处理重连和扩展。
Q&A
SignalR是什么?它主要解决什么问题?
SignalR是ASP.NET Core的实时通信库,允许服务器向客户端推送消息,而不是让客户端轮询。它解决了轮询浪费带宽、延迟高、难以扩展的问题,提供了推送式更新、自动传输协商、连接管理、分组和横向扩展等功能。
SignalR支持哪些传输协议?它是如何选择传输方式的?
SignalR支持WebSocket、Server-Sent Events (SSE)和长轮询。它会根据客户端、服务器及中间代理的支持情况自动协商最佳传输协议,优先WebSocket,然后降级到SSE,最后是长轮询。
如何在SignalR中实现分组消息发送?
在Hub中,可以使用Groups.AddToGroupAsync将连接加入分组,使用Clients.Group(roomName).SendAsync向分组发送消息。分组由服务器管理,重连后需要重新加入。
什么是强类型Hub?它有什么好处?
强类型Hub通过定义接口(如IChatClient)来声明客户端方法,使用Hub<IChatClient>,这样调用客户端方法时会有编译期检查,避免字符串方法名拼写错误,并提供IntelliSense提示。
SignalR如何实现横向扩展?Redis和Azure SignalR Service有什么区别?
SignalR默认将连接状态保存在单进程内存中,多实例部署时需要Backplane。Redis Backplane通过共享消息代理同步消息;Azure SignalR Service是托管服务,客户端直接连接Azure,应用服务器只需发布消息,无需自建Backplane,也避免了粘性会话问题。
SignalR中如何传递身份验证令牌?
由于浏览器无法在WebSocket握手请求中附加自定义请求头,SignalR JS客户端通过查询字符串参数传递令牌,服务器需要在JWT Bearer事件中从查询字符串读取access_token,并配置路径匹配。
SignalR与原生WebSocket和gRPC流式传输相比,有什么优缺点?
SignalR自动处理传输降级、重连和扩展,适合Web应用实时功能;原生WebSocket需要自己处理帧、重连和扩展,但控制力强;gRPC流式传输适合内部服务间通信,不支持浏览器。