最近协助蟹老板升级新框架,维护基础设施服务,目前已经稳了。
早上蟹老板看到我进入公司,马上就叫停我,说我为什么左脚先进公司,你这样会让我很难做耶,这样把我给你一次机会把现在的消息服务重构了,我就放过你这一次。(当时我都没有反应过来,蟹老板就准备和我讲需求了,我赶紧着小本子开始记需求)

我们需要记录所有用户的在线状况(登录的设备存在多个设备同时登录) 、指定用户下线 、实时接收消息技术你可以自由技术发挥,今天中午之前给我一个设计概要。(呜呜,天空是蔚蓝色、窗外还有千纸鹤)
ASP.NET Core SignalR 的一些功能
SignalR支持如下的方式实现实时通信(SignalR会自动选择服务器和客户端能力范围内的最佳通信方式)
SignalR核心
Hub 是一种高级管道,允许客户端和服务器相互调用方法。 SignalR 自动处理跨计算机边界的调度,并允许客户端调用服务器上的方法,反之亦然。 可以将强类型参数传递给方法,从而支持模型绑定。 SignalR 提供两种内置中心协议:基于 JSON 的文本协议和基于 SignalR 的二进制协议。 与 JSON 相比,MessagePack 通常会创建更小的消息。 旧版浏览器必须支持 XHR 级别 2 才能提供 MessagePack 协议支持。
中心通过发送包含客户端方法的名称和参数的消息来调用客户端代码。 作为方法参数发送的对象使用配置的协议进行反序列化。 客户端尝试将名称与客户端代码中的方法匹配。 当客户端找到匹配项时,它会调用该方法并将反序列化的参数数据传递给它。
| 属性 | 说明 |
|---|---|
| ConnectionId | 获取连接的唯一 ID(由 SignalR 分配)。 每个连接有一个连接 ID。 |
| UserIdentifier | 获取用户标识符。 默认情况下,SignalR 使用与连接关联的 ClaimsPrincipal 中的 ClaimTypes.NameIdentifier 作为用户标识符。 |
| User | 获取与当前用户关联的 ClaimsPrincipal。 |
| Items | 获取可用于在此连接范围内共享数据的键/值集合。 数据可以存储在此集合中,会在不同的中心方法调用间为连接持久保存。 |
| Features | 获取连接上可用的功能的集合。 目前,在大多数情况下不需要此集合,因此未对其进行详细记录。 |
| ConnectionAborted | 获取一个 CancellationToken,它会在连接中止时发出通知。 |
Hub.Context还包含以下方法
| 方法 | 说明 |
|---|---|
| GetHttpContext | 返回连接的 HttpContext,如果连接不与 HTTP 请求关联,则返回 null。 对于 HTTP 连接,可以使用此方法获取 HTTP 标头和查询字符串等信息。 |
| Abort | 中止连接。 |
Hub 类具有一个 Clients 属性,该属性包含适用于服务器与客户端之间的通信的以下属性
| 属性 | 说明 |
|---|---|
| All | 对所有连接的客户端调用方法 |
| Caller | 对调用了中心方法的客户端调用方法 |
| Others | 对所有连接的客户端调用方法(调用了方法的客户端除外) |
Hub.Clients还包含以下方法
| 方法 | 说明 |
|---|---|
| AllExcept | 对所有连接的客户端调用方法(指定连接除外) |
| Client | 对连接的一个特定客户端调用方法 |
| Clients | 对连接的多个特定客户端调用方法 |
| Group | 对指定组中的所有连接调用方法 |
| GroupExcept | 对指定组中的所有连接调用方法(指定连接除外) |
| Groups | 对多个连接组调用方法 |
| OthersInGroup | 对一个连接组调用方法(不包括调用了中心方法的客户端) |
| User | 对与一个特定用户关联的所有连接调用方法 |
| Users | 对与多个指定用户关联的所有连接调用方法 |
使用SignalR与客户端进行实时通讯、用户链接管理、JWt进行用户身份认证和鉴权、Redis保存用户链接信息
OnConnectedAsync()方法,这样我们就可以通过获取当前的连接IP信息和用户浏览器信息组成一个唯一设备标识。Hashes将用户Id当成key,然后将不同设备登录用户当成value存储。OnDisconnectedAsync()方法,就代表该设备的用户下线了。前端使用@aspnet/signalr与服务端进行握手通讯,用户登录成功建立一个Socket链接
// 创建链接this.init.connection = new signalR.HubConnectionBuilder()// IM_URL链接地址 .withUrl(IM_URL, {// accessTokenFactory携带用户Token进行身份认证和鉴权 accessTokenFactory: () => this.token}).build();方式客户端发生意外断线,或者后端断开我们的链接,我们就可以监听关闭事件,给到用户一些提示
this.init.connection.onclose(function() { console.log('connecition closed');});因为我自己写过一个IM的小应用,自己就也写过前端,所以这里我会给一些经验给到前端大佬。
思路是这样的:前端程序初始化Signalr接收消息方法的时候带一个参数(类似委托的参数),这个委托是一个消息类型处理工厂。
App.Vue 文件中的代码
methods: {// 接受用户信息进入消息总线ReceiveUserMsg(data) {....处理消息工厂代码..... switch (switch_on) { case "消息类型" : break; }}},created() { try { // 初始化创建链接 this.$signalr.CreatorConnectServer(); // 初始化用户消息接收 this.$signalr.ReUserReceiveMessage(this.ReceiveUserMsg); // 初始化链接关闭事件 this.$signalr.OnClose(); } catch (e) {console.log("网络错误");}}signalr.js(自己专门封装的一个js)
// 接受信息ReUserReceiveMessage(receiveUserMsg) {this.init.connection.on("ReUserReceiveMessage", (result) => { // 执行委托 receiveUserMsg(result); console.log(result) });}