一、SiganlR 使用的协议类型
- 1.websocket即时通讯协议
- 2.Server-Sent Events(SSE)服务器事件
- 3.longpolling 长轮询。
如果客户端禁用协商,只能websocket协议。
二、连接过程
- 客户端未禁用协商
- 客户端禁用协商
- 客户端直接发送 websocket 请求,建立连接。
//客户端建立signalr连接时,指定配置参数,禁用协商。 const options = { skipNegotiation: true,//是否跳过协商过程 transport: signalR.HttpTransportType.WebSockets,//直接指定使用websocket协议 }; connection = new signalR.HubConnectionBuilder() .withUrl("https://localhost:7002/Hubs/ChatRoomHub",options) .withAutomaticReconnect() //自动重连 .build();
三、身份认证
- websocket协议 无请求报文头headers,token只能放 QueryString 中,一般参数名定为 access_token。
- 在 Hub中引入身份认证服务,Hub OnConnectedAsync()中,即建立连接时,通过身份认证服务解析token是否合法并拿到用户信息。
四、分布式部署问题
问题1. 多节点环境,客户端协商过程,可能请求到不同服务器。
@H_502_10@如果有AB两个服务器负载,在协商过程时客户端第一次http请求A,A服务器记录了客户端连接信息上下文。
客户端第二次ws连接发送到B服务器,而B服务器没有客户端连接信息上下文,就出错了。
方式1. 粘性会话
@H_502_10@网关服务器 或 负载均衡服务器 进行配置,把来自同一个客户端的请求都转发给同一台服务器。- 优点:兼容性最好,客户端按兼容性依次选择协议
- 缺点:公网ip没办法平均分配,很难控制。
方式2. 禁用协商
@H_502_10@客户端连接时设置禁用协商,连接时仅一次ws请求。- 缺点:只能适用于兼容websocket的浏览器 只能使用websocket协议,无法使用 sse 和 longpolling
问题2. 多节点环境,消息不能跨服务器连接发送。
@H_502_10@A服务器向全部连接发消息,只能发送到连接A服务器的客户端,不能发送给连接到B服务器的客户端。- 解决办法:引入 Microsoft.AspNetCore.SignalR.StackExchangeRedis 包,注入分布式SignalR服务到DI中。
作用:在多个服务器实例之间共享消息和连接状态。确保跨服务器实例的连接同步和消息传递。services.AddSignalR(o => { o.EnableDetailedErrors = true;//详细异常信息 o.HandshakeTimeout = TimeSpan.FromSeconds(30);//握手超时时间 }).AddStackExchangeRedis("{redis连接字符串}", opt => { opt.Configuration.ChannelPrefix = "{RedisKey前缀}"; });//分布式 SignalR 消息
问题3. 在后台任务中使用Hub推送消息。
- 1.建立连接,从token中拿到用户信息。(分布式环境,多节点负载时,更新缓存需要加锁)
- 2.断开连接,从缓存中移除 当前连接id。(分布式环境,多节点负载时,更新缓存需要加锁)
- 3.后台任务
- 注入分布式SignalR服务
- 注入Hub服务
- 业务中拿到要接收消息的 用户id集合
- 从缓存中找到对应的 全部连接id
- 调Hub向连接id推送SignalR消息
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。