使用ABP SignalR重构消息服务(一)
使用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重构消息服务(一)的更多相关文章
- 使用ABP SignalR重构消息服务(二)
使用ABP SignalR重构消息服务(二) 上篇使用ABP SignalR重构消息服务(一)主要讲的是SignalR的基础知识和前端如何使用SignalR,这段时间也是落实方案设计.这篇我主要讲解S ...
- 基于SignalR的消息推送与二维码描登录实现
1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...
- X-Admin&ABP框架开发-消息通知
业务型网站使用过程中,消息通知是一个不可或缺的功能,采用站内通知.短信通知.邮件通知.微信通知等等各种方式都有,ABP框架对这部分工作已经封装的很好了,站在巨人的肩膀上,一览全貌,带来的就是心情舒畅. ...
- AngularJS+ASP.NET MVC+SignalR实现消息推送
原文:AngularJS+ASP.NET MVC+SignalR实现消息推送 背景 OA管理系统中,员工提交申请单,消息实时通知到相关人员及时进行审批,审批之后将结果推送给用户. 技术选择 最开始发现 ...
- 实时显示数据 SignalR 及时消息提醒( 立即向其推送内容)
实时显示数据 SignalR 及时消息提醒( 立即向其推送内容) http://www.cnblogs.com/Leo_wl/p/5634910.html <!--Reference the ...
- Signalr实现消息推送
一.前言 大多数系统里面好像都有获取消息的功能,但这些消息来源都不是实时的,比如你开两个浏览器,用两个不同的账号登录,用一个账号给另外一个账号发送消息,然而并不会实时收到消息,必须要自己手动F5刷新一 ...
- [2017-10-25]Abp系列——集成消息队列功能(基于Rebus.Rabbitmq)
本系列目录:Abp介绍和经验分享-目录 前言 由于提交给ABP作者的集成消息队列机制的PR还未Review完成,本篇以Abplus中的代码为基准来介绍ABP集成消息队列机制的方案. Why 为什么需要 ...
- 消息服务MNS和消息队列ONS产品对比
消息服务MNS和消息队列ONS产品对比 MNS已经进过严格测试,已达到商业化的稳定性要求,其主要特点和适用场景 1.数据高可靠(10个9),对于数据可靠性敏感(要求消息数据不丢)的应用场景建议选择. ...
- JMS(Java消息服务)入门教程
什么是Java消息服务 Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建.发送.读取消息等,用于支持JAVA应用程序开发.在J2EE中 ...
随机推荐
- 如何实现固定宽高的DOM元素的水平垂直居中
效果:
- Python—列表元组和字典
Python-列表元组和字典 列表 元组 字典 列表: 列表是Python中的一种数据结构,他可以存储不同类型的数据.尽量存储同一种类型 列表索引是从0开始的,我们可以通过索引来访问列表的值. 列表的 ...
- Docker prefereces
https://docs.docker.com/docker-for-mac/#preferences-menu docker 的镜像命令需要抽时间了解
- SQLServer、Mysql、Oracle 创建、删除用户和授予用户权限
SQLServer 1.创建用户 CREATE LOGIN [用户名称] WITH PASSWORD='用户密码', DEFAULT_DATABASE=[默认数据库名称], CHECK_EXPIRAT ...
- Solution -「CF 1023F」Mobile Phone Network
\(\mathcal{Description}\) Link. 有一个 \(n\) 个结点的图,并给定 \(m_1\) 条无向带权黑边,\(m_2\) 条无向无权白边.你需要为每条白边指定边权 ...
- CentOS 7 编译部署LAMP环境
文章目录 1.需求以及环境准备 1.1.版本需求 1.2.环境准备 1.3.安装包准备 2.编译升级Openssl 2.1.查看当前Openssl版本 2.2.备份当前版本Openssl文件 2.3. ...
- Python中random模块的用法案例
1 import random # 调用random模块 2 3 a = random.random() # 随机从0-1之间抽取一个小数 4 print(a) 5 6 a = random.rand ...
- 【Elastic-2】SpringBoot整合ELK、SpringBoot写ES
ELK相关TODO 快速开始文档(https://www.cnblogs.com/lbhym/p/15934416.html) SpringBoot整合ELK ELK接入Kafka(待Kafka快速开 ...
- OpenGL/ES关于像素渲染
知道着色器的人都会知道一个东西,那就是着色器分为顶点着色器与片元着色器.在移动端真正渲染到手机屏幕上的无非是一些颜色值,但是一个片元是大于一个像素的,一个片元可能包含多个像素,当然一个片元所包含的像素 ...
- [题解]BZOJ1004 序列函数
原题找不到了,应该是usaco之类的题目吧.给一个可以交题的链接:http://www.cqoi.net:2012/problem.php?id=1004 思路:将素数一个一个往里乘,保证扫描的顺序是 ...