消息推送方案

221 阅读4分钟

1.背景

后台有时需要实时的获取服务器消息,比如:实时的消息推送功能,比如聊天室、后台信息提示、实时更新数据等功能。对于此类需求,一种较为原始的方式就是让客户端每隔一段时间主动去轮询服务器。但是这种做法有一个很大的弊端:如果客户端的数量很大,每隔一段时间就发消息给服务器的话,服务器的压力会非常大。而且访问的频度也很难精确把握,过于频繁的访问服务器,则服务器压力太大;不频繁的访问,数据更新可能又不及时。

综上所述,这就需要服务器与客户端长时间建立一个通信连接,但默认HTTP协议只支持请求响应模式,不容易完成以上功能。

2.方案调研

服务器与客户端需要长时间建立一个通信连接,可以有以下几种方式:

  1. polling(轮询)
  2. Long polling
  3. HTML5中定义的websocket

2.1 polling(轮询)

polling(轮询)是指不管服务器端有没有更新,客户端(通常指浏览器)都定时的发送请求进行查询。

2.1.1 优缺点

优点:后端程序编写比较容易

缺点:请求中有大部分都无用,浪费带宽和服务器资源

2.2 Long polling(长轮询)

Long polling(长轮询)的服务,客户端是不做轮询的,客户端在发起一次请求后立即挂起,一直到服务器端有更新的时候,服务器才会主动推送消息给客户端。客户端处理完响应信息后再向服务器发送新的请求。

2.2.1 优缺点

优点: 在无消息的情况下不会频繁的请求,耗费资源小

缺点: 服务器保持连接会消耗资源,返回数据无顺序保证,难于管理维护

2.3 websocket

websocket 协议是HTML5定义的一种新协议,它实现了浏览器与服务器全双工通信。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。

image.png websocket主要就是三步:

  1. 建立连接
  2. 开始通信
  3. 结束通信

2.3.1 优缺点

  1. 优点: 双向发送或者接收消息 服务支持友好,Tomcat7.0.5开始支持websocket
  2. 缺点:少部分浏览器不支持,浏览器支持的程度与方式有区别

4. 功能说明

  • 系统右上角铃铛消息,点击消息主动查看消息
  • websocket 及时通知消息,当前正在使用系统,收到消息会立即弹出
  • 消息路由跳转,在消息通知后,我们需要定位消息到对应的页面去查看对应的数据

4.1. 发送消息

发送发后对应的接收人可点击🔔查看消息

image.png

4.2. 及时消息

在保存系统消息的同时发出一条websocket消息,前端收到消息立即弹出消息通知

image.png

4.3.消息路由跳转

4.3.1 动态路由跳转示例

点击消息到指定的页面并携带动态参数进行查询指定数据 image.png

4.3.2 管理配置路由

进入系统的字典功能中,配置消息类型:

  1. 标题,弹出消息展示的标题
  2. 路由,跳转到页面的地址(管理端默认所用该字段路由)
  3. 路由二, 备用(同一条消息存在多端展示的备有路由跳转字段)

image.png

4.3.3 发送消息(添加动态参数)

消息发送时参数:

  1. 业务类型,对应的字典配置,将自动从字典中获取标题以及路由信息
  2. 路由动态参数,跳转路由后的自带的查询参数

4.3.4 跳转后页面获取动态参数

  1. 跳转页面后,查询数据需要获取携带的动态参数来进行查询。
  2. 客户端监听路由参数变化发起查询。

8.客户端

  1. 消息设置

image.png

  1. 跳转后页面获取动态参数处理

9.websocket方案

基于socket.io 做一层封装,加入服务鉴权等逻辑。

9.1 暴露外部的API

  1. 接收消息 - emit
  2. 发送消息 - on
  3. 关闭连接 - close

9.1.2 接入方式

// 安装
$ npm install @xxx/websocket-sdk --save

$ yarn add @xxx/websocket-sdk --save

// 引入sdk
import WebsocketSdk from '@xxx/websocket-sdk'

// 实例化
let ws = new WebsocketSdk({})

9.1.3 使用方式

import WebsocketSdk from '@xxx/websocket-sdk'

const ws = new WebsocketSdk({
    url: "wss://*******"auth: {...}, // 鉴权标识
    query: {} //参数
})

// 接收服务端消息
ws.emit = evt => {
    console.log(evt, 'onMessage')
}

// 向服务端发送消息
ws.on(data={}, actionType, isLogin)

9.1.4 完整流程

image.png