使用ABP SignalR重构消息服务

最近协助蟹老板升级新框架,维护基础设施服务,目前已经稳了。

早上蟹老板看到我进入公司,马上就叫停我,说我为什么左脚先进公司,你这样会让我很难做耶,这样把我给你一次机会把现在的消息服务重构了,我就放过你这一次。(当时我都没有反应过来,蟹老板就准备和我讲需求了,我赶紧着小本子开始记需求)

背景

我们需要记录所有用户的在线状况(登录的设备存在多个设备同时登录)指定用户下线实时接收消息技术你可以自由技术发挥,今天中午之前给我一个设计概要。(呜呜,天空是蔚蓝色、窗外还有千纸鹤)

技术点

  • SignalR

    SignalR 是一个开放源代码库,可用于简化向应用添加实时 Web 功能。 实时 Web 功能使服务器端代码能够将内容推送到客户端。
  • Redis

    Redis 是一个开源(BSD 许可)的内存数据结构存储,用作数据库、缓存和消息代理。
  • Jwt

    JSON Web Token (JWT) 是一个开放标准 ( RFC 7519 ),它定义了一种紧凑且自包含的方式,用于在各方之间以 JSON 对象的形式安全传输信息。此信息可以验证和信任,因为它是数字签名的。JWT 可以使用密钥(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

为什么使用SignalR

  • ASP.NET Core SignalR 的一些功能

    • 自动处理连接管理。
    • 同时向所有连接的客户端发送消息。 例如聊天室。
    • 向特定客户端或客户端组发送消息。
    • 对其进行缩放,以处理不断增加的流量。
  • SignalR支持如下的方式实现实时通信(SignalR会自动选择服务器和客户端能力范围内的最佳通信方式)

    • WebSockets:是一种在单个TCP连接上进行全双工通信的协议,使得服务器和浏览器的通信更加简单,服务端可以主动发送信息。
    • Server-Sent Events:SSE 与 WebSocket 作用相似,都是建立浏览器与服务器之间的通信渠道,然后服务器向浏览器推送信息。WebSocket是双向的,而SSE是单向的。
    • Long Polling(长轮询) :和传统的轮询原理一样,只是服务端不会每次都返回响应信息,只有有数据或超时了才会返回,从而减少了请求次数。
  • SignalR核心

    • Hub 是一种高级管道,允许客户端和服务器相互调用方法。 SignalR 自动处理跨计算机边界的调度,并允许客户端调用服务器上的方法,反之亦然。 可以将强类型参数传递给方法,从而支持模型绑定。 SignalR 提供两种内置中心协议:基于 JSON 的文本协议和基于 SignalR 的二进制协议。 与 JSON 相比,MessagePack 通常会创建更小的消息。 旧版浏览器必须支持 XHR 级别 2 才能提供 MessagePack 协议支持。

    • 中心通过发送包含客户端方法的名称和参数的消息来调用客户端代码。 作为方法参数发送的对象使用配置的协议进行反序列化。 客户端尝试将名称与客户端代码中的方法匹配。 当客户端找到匹配项时,它会调用该方法并将反序列化的参数数据传递给它。

Hubs(集线器)介绍

  • Hub.Context

    Hub 类具有一个 Context 属性,该属性包含具有连接相关信息的以下属性
属性 说明
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

Hub 类具有一个 Clients 属性,该属性包含适用于服务器与客户端之间的通信的以下属性

属性 说明
All 对所有连接的客户端调用方法
Caller 对调用了中心方法的客户端调用方法
Others 对所有连接的客户端调用方法(调用了方法的客户端除外)

Hub.Clients还包含以下方法

方法 说明
AllExcept 对所有连接的客户端调用方法(指定连接除外)
Client 对连接的一个特定客户端调用方法
Clients 对连接的多个特定客户端调用方法
Group 对指定组中的所有连接调用方法
GroupExcept 对指定组中的所有连接调用方法(指定连接除外)
Groups 对多个连接组调用方法
OthersInGroup 对一个连接组调用方法(不包括调用了中心方法的客户端)
User 对与一个特定用户关联的所有连接调用方法
Users 对与多个指定用户关联的所有连接调用方法

设计思路

使用SignalR与客户端进行实时通讯、用户链接管理、JWt进行用户身份认证和鉴权、Redis保存用户链接信息

  • 前端创建链接之后就会触发后端OnConnectedAsync()方法,这样我们就可以通过获取当前的连接IP信息和用户浏览器信息组成一个唯一设备标识。
  • 我们创建一个Redis key数据类型为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)
});
}

使用ABP SignalR重构消息服务(一)的更多相关文章

  1. 使用ABP SignalR重构消息服务(二)

    使用ABP SignalR重构消息服务(二) 上篇使用ABP SignalR重构消息服务(一)主要讲的是SignalR的基础知识和前端如何使用SignalR,这段时间也是落实方案设计.这篇我主要讲解S ...

  2. 基于SignalR的消息推送与二维码描登录实现

    1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...

  3. X-Admin&ABP框架开发-消息通知

    业务型网站使用过程中,消息通知是一个不可或缺的功能,采用站内通知.短信通知.邮件通知.微信通知等等各种方式都有,ABP框架对这部分工作已经封装的很好了,站在巨人的肩膀上,一览全貌,带来的就是心情舒畅. ...

  4. AngularJS+ASP.NET MVC+SignalR实现消息推送

    原文:AngularJS+ASP.NET MVC+SignalR实现消息推送 背景 OA管理系统中,员工提交申请单,消息实时通知到相关人员及时进行审批,审批之后将结果推送给用户. 技术选择 最开始发现 ...

  5. 实时显示数据 SignalR 及时消息提醒( 立即向其推送内容)

    实时显示数据  SignalR 及时消息提醒( 立即向其推送内容) http://www.cnblogs.com/Leo_wl/p/5634910.html  <!--Reference the ...

  6. Signalr实现消息推送

    一.前言 大多数系统里面好像都有获取消息的功能,但这些消息来源都不是实时的,比如你开两个浏览器,用两个不同的账号登录,用一个账号给另外一个账号发送消息,然而并不会实时收到消息,必须要自己手动F5刷新一 ...

  7. [2017-10-25]Abp系列——集成消息队列功能(基于Rebus.Rabbitmq)

    本系列目录:Abp介绍和经验分享-目录 前言 由于提交给ABP作者的集成消息队列机制的PR还未Review完成,本篇以Abplus中的代码为基准来介绍ABP集成消息队列机制的方案. Why 为什么需要 ...

  8. 消息服务MNS和消息队列ONS产品对比

    消息服务MNS和消息队列ONS产品对比 MNS已经进过严格测试,已达到商业化的稳定性要求,其主要特点和适用场景 1.数据高可靠(10个9),对于数据可靠性敏感(要求消息数据不丢)的应用场景建议选择. ...

  9. JMS(Java消息服务)入门教程

    什么是Java消息服务 Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建.发送.读取消息等,用于支持JAVA应用程序开发.在J2EE中 ...

随机推荐

  1. NoSQL 之 Redis配置与优化

    NoSQL 之 Redis配置与优化 1.关系数据库与非关系型数据库概述 2.关系数据库与非关系型数据库区别 3.非关系型数据库产生背景 4.Redis简介 5.Redis安装部署 6.Redis 命 ...

  2. Shell双重循环、图形排列及九九乘法表

    Shell双重循环.图形排列及九九乘法表 目录 Shell双重循环.图形排列及九九乘法表 一.双重循环 1. 双重循环概述 2. 双重循环结构 二.循环特殊操作 1. exit 2. break 3. ...

  3. python进阶(24)Python字典的底层原理以及字典效率

    前言 问题1:python中的字典到底是有序还是无序 问题2:python中字典的效率如何 python字典底层原理   在Python 3.5以前,字典是不能保证顺序的,键值对A先插入字典,键值对B ...

  4. 年前最后一次2022.1.28_RP++

    T1同昨(我看到题目就粘上昨天的代码,结果题还没发我就A了hhhhhh) T2一开始想用深搜,结果T掉了...只好改广搜,就挺令人头大 点击查看宽广对比 #include<bits/stdc++ ...

  5. 高可用 & 七层负载均衡与四层负载均衡

    内容概要 高可用 七层负载均衡 和 四层负载均衡 内容详细 一.高可用 1.什么是高可用 一般是指2台机器启动着完全相同的业务系统,当有一台机器down机了,另外一台服务器就能快速的接管,对于访问的用 ...

  6. Solution Set -「LOCAL」冲刺省选 Round XXII

    \(\mathscr{Summary}\)   和出题人很有缘分但是没有珍惜.jpg   A 题有一个显然的二维偏序斜率式,以及显然的 CDQ 套李超树 \(\mathcal O(n\log^2n)\ ...

  7. [LeetCode]1295. 统计位数为偶数的数字

    给你一个整数数组 nums,请你返回其中位数为 偶数 的数字的个数. 示例 1: 输入:nums = [12,345,2,6,7896] 输出:2 解释: 12 是 2 位数字(位数为偶数)  345 ...

  8. 在 CentOS 或 RHEL 系统上检查可用的安全更新的方法

    当你更新系统时,根据你所在公司的安全策略,有时候可能只需要打上与安全相关的补丁.大多数情况下,这应该是出于程序兼容性方面的考量.那该怎样实践呢?有没有办法让 yum 只安装安全补丁呢? 答案是肯定的, ...

  9. 【C# 线程】数据槽 LocalDataStoreSlot简称DataSlot

    背景 为了确保在线程中声明特定类型的变量,在每个线程中的值都是唯一的,不受到其他线程对该变量读写的影响.也就是俗称的线程本地存储 (TLS),可用于存储对线程和应用程序域唯一的数据. 例如:主线程中声 ...

  10. 【基础知识】Intel CPU体系结构|x86是什么意思

    看了<计算机系统结构>.<深入理解计算机系统>.<大话处理器>等经典书籍,也在google上搜了一大堆资料,前前后后.断断续续的折腾了一个多月,终于想通了,现在把自 ...