- A+
所属分类:.NET技术
一、SiganlR 使用的协议类型
- 1.websocket即时通讯协议
- 2.Server-Sent Events(SSE)服务器事件
- 3.longpolling 长轮询。
如果客户端开启协商,会按顺序选择可兼容的协议。(默认开启协议协商)
如果客户端禁用协商,只能websocket协议。
二、连接过程
- 1.http 协议协商过程 客户端向服务器发http请求连接,询问服务器支持什么协议。
服务端返回支持的协议类型,并分配ConnectionId。(未禁用协议协商时有) - 2.ws 客户端确认协议后发送ws请求,建立连接。
三、身份认证
- websocket协议 无请求报文头headers,token只能放 QueryString 中,一般参数名定为 access_token。
- 在 Hub中引入身份认证服务,Hub OnConnectedAsync()中,即建立连接时,通过身份认证服务解析token是否合法并拿到用户信息。
四、集群、分布式部署问题
问题1. 多个服务器集群环境,客户端协商过程,可能请求到不同服务器。
在协商过程,如果有AB两个服务器集群
客户端第一次http请求A,A服务器记录了客户端连接信息上下文。
客户端第二次ws连接发送到B服务器,而B服务器没有客户端连接信息上下文,就出错了。
方式1. 粘性会话
网关服务器 或 负载均衡服务器 进行配置,把来自同一个客户端的请求都转发给同一台服务器。
- 优点:兼容性最好,客户端按兼容性依次选择协议
- 缺点:公网ip没办法平均分配,很难控制。
方式2. 禁用协商
客户端连接时设置禁用协商,连接时仅一次ws请求。
- 缺点:只能适用于兼容websocket的浏览器 只能使用websocket协议,无法使用 sse 和 longpolling
问题2. 集群环境 消息不能跨服务器连接发送。
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中拿到用户信息。
- 缓存: 用户id - [连接id集合]
- 缓存: 连接id - 用户id
- 2.断开连接,从缓存中移除 当前连接id
- 3.后台任务
- 注入分布式SignalR服务
- 注入Hub服务
- 业务中拿到要接收消息的 用户id集合
- 从缓存中找到对应的 全部连接id
- 调Hub向连接id推送SignalR消息