赞
踩
之前做个一个功能,通过websocket长链接接收后台推送的数据,然后在前端动态渲染。一直没来的及输出个文档,现在输出一下。
WebSocket 是一种在 Web 应用中实现实时通信的方法,它可以在客户端和服务器端之间建立长连接,实现实时消息传递。
传统的WenSocket在使用过程中可能会有各种问题,什么性能方面啊、浏览器兼容方面啊,各种问题。之前做个一版用传统的WebSocket实现车辆实时位置推送功能,因为后台是广播模式进行的消息推送,一辆车一个通道,当车的数量多起来后,浏览器或WebSocket就直接罢工了,我实测了一下,这个边界值大概在253 - 256。所以,急需更换方案。
SockJS 和 Stomp 是两个常用的 WebSocket 库,它们可以帮助我们更方便地实现 WebSocket 功能。相较于传统的WebSocket,它的优点有很多:
兼容性更好:能够在浏览器和服务器之间创建低延迟、双向通信通道,能够兼容大多数浏览器和服务器,包括一些老旧的浏览器和服务器。
自适应性更强:能够根据环境和浏览器自动选择最佳的通信方式,包括WebSocket、XHR流或JSONP轮询等。这样能够更好的保证通信的质量和稳定性。
底层通信更加可靠:使用了一些底层通信协议,例如XHR流或JSONP轮询,它们能够更好的处理网络故障、代理服务器等问题,从而提高通信的可靠性。
开发效率更高:提供了一些高级的功能,例如订阅和发布模式、心跳检测等,能够更快速地开发实时Web应用程序。
跨语言和平台更容易:STOMP协议是一种基于文本的协议,因此它能够更容易地跨语言和平台通信。这意味着您可以使用不同的编程语言和框架来构建您的Web应用程序,并且能够无缝地集成在一起。
总之,使用SockJS + STOMPJS相较于传统模式的Websocket能够更好的保证通信的质量和稳定性,同时能够提高开发效率,从而更好地满足实时Web应用程序的需求。
SockJS
SockJS 是一个 JavaScript 库,用于在浏览器和 Web 服务器之间建立实时通信连接。它提供了一个 WebSocket 的备选方案,并兼容多种浏览器和 Web 服务器。SockJS 会自动检测浏览器是否支持 WebSocket,如果不支持,则会自动降级为其他协议(如 long polling、iframe、JSONP 等)。
Stomp
Stomp 是一种简单的消息传递协议,它允许客户端和服务器之间进行异步消息传递。Stomp 协议定义了一个消息格式,允许客户端和服务器进行消息的订阅和发布。Stomp 可以在 Web 应用中使用,也可以在其他应用中使用(如 Android、iOS 等)。
- 上代码 -
1. 引入 SockJS 和 Stomp 库
- npm install sockjs-client --save
-
- npm install stompjs --save
- import SockJS from "sockjs-client";
- import Stomp from "stompjs";
2、类实现
- class webSocket {
- //构造函数
- constructor() {
- this.tryTimes = 1; // 重连次数
- this.callback = null; // 回调函数
- this.stompClient = null; // stomp对象
- this.reconTimeout = null; //重连延时器
- this.sendTimeout = null; // 重发心跳延时器 - 10s发一次
- this.vm = null;
- }
-
- /** socket连接 */
- connectionSocket() {
- //连接SockJS
- let socket = new SockJS(`${this.getSocketUrl()}`);
-
- // 获取STOMP子协议的客户端对象
- this.stompClient = Stomp.over(socket);
-
- //日志不打印
- this.stompClient.debug = () => {};
-
- // 向服务器发起websocket连接
- this.stompClient.connect({ userId: '自己订阅送的id' }, () => {
- //tryTimes定义重置
- this.tryTimes = 1;
- //订阅消息
- this.subscribeToServer();
- //心跳单独通道
- this.stompClient.subscribe(`/server/net/${'自己订阅送的id'}`, (response) => {
- if (response && response.body && JSON.parse(response.body).code == '0') {
- //再次进行心跳发送
- this.heartCheck();
- }
- });
- }, (err) => {
- // 连接发生错误时的处理函数
- console.log('失败');
- if(this.vm.$message) this.vm.$message({ message: '连接发生错误,请刷新网页再次连接!', type: 'warning' });
- });
- }
- /** 订阅服务端 */
- subscribeToServer() {
- // 订阅服务端提供的某个topic
- this.stompClient.subscribe(`/server/${topic的id}`, (response) => {
- if (response) {
- if(this.callback) this.callback(response);
- }
- });
- }
-
- /** 赋值、初始化socket */
- initWebSocket(back, me) {
- this.vm = me;
- //列表赋值
- this.callback = back;
- //初始化连接
- this.connectionSocket();
- //加载心跳
- this.heartCheck();
- }
-
- /** 重连 */
- reconnect() {
- this.destroy();
- if(this.tryTimes > 10) {
- if(this.vm.$message) this.vm.$message({ message: '重连次数已达上限,连接失败。请刷新网页再次连接!', type: 'warning' });
- return;
- }
- this.tryTimes++;
- //再次连接
- this.connectionSocket();
- this.heartCheck();
- }
-
- /** 心跳检测机制 */
- heartCheck() {
- //先清除重连机制
- if(this.reconTimeout) clearTimeout(this.reconTimeout);
- let me = this;
- me.sendTimeout = setTimeout(() => {
- me.sendSocket({ to: `/server/net/${'自己订阅送的id'}` });
- //重连机制,十秒不被清除代表已经断开,进行重连
- me.reconTimeout = setTimeout(() => {
- me.reconnect();
- }, 10000);
- }, 10000);
- }
-
- /** 发送消息 */
- sendSocket(params) {
- try {
- this.stompClient.send("/client/path/points", {}, JSON.stringify(params));
- } catch (error) {
- console.log("发生异常了-------", error);
- }
- }
-
- /** 销毁 */
- destroy() {
- // 断开连接,清除定时器
- if (this.stompClient) this.stompClient.disconnect();
- if (this.reconTimeout) clearTimeout(this.reconTimeout);
- if (this.sendTimeout) clearTimeout(this.sendTimeout);
- }
-
- /** 获取动态socket地址,http环境下使用http,https环境下使用https访问websocket */
- getSocketUrl() {
- return window.location.protocol + '//' + process.env.VUE_APP_WS_API + process.env.VUE_APP_WS_CTX;
- }
- }
- const WebSocket = new webSocket();
- export default WebSocket;
3、使用
- //webSockets类
- webSockets.initWebSocket((res) => {
- console.log("推送的消息------", res);
- }, this)
4、记得在不用的时候干掉订阅
- destroyed() {
- //离开页面,干掉websocket
- webSockets.destroy();
- },
代码中去除了部分的业务逻辑代码,按照需求添加即可。如果是想要一通道多订阅的话,可让后台搞一个动态的topic,给方法内扔一个数组进去,遍历数组,生成多个订阅。
ok,结束,我的愿望是世界和平!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。