使用websocket实时通信
在react中使用websocket不需要引入其他库,只需要创建一个公共组件,封装一下websocket
创建公共组件
websocket.js
let websocket, lockReconnect = false; let createWebSocket = (url) => { websocket = new WebSocket(url); websocket.onopen = function () { heartCheck.reset().start(); } websocket.onerror = function () { reconnect(url); }; websocket.onclose = function (e) { console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean) } websocket.onmessage = function (event) { lockReconnect=true; //event 为服务端传输的消息,在这里可以处理 } } let reconnect = (url) => { if (lockReconnect) return; //没连接上会一直重连,设置延迟避免请求过多 setTimeout(function () { createWebSocket(url); lockReconnect = false; }, 4000); } let heartCheck = { timeout: 60000, //60秒 timeoutObj: null, reset: function () { clearInterval(this.timeoutObj); return this; }, start: function () { this.timeoutObj = setInterval(function () { //这里发送一个心跳,后端收到后,返回一个心跳消息, //onmessage拿到返回的心跳就说明连接正常 websocket.send("HeartBeat"); }, this.timeout) } } //关闭连接 let closeWebSocket=()=> { websocket && websocket.close(); } export { websocket, createWebSocket, closeWebSocket };
在react组件中的使用
1.react 函数组件的使用
import {createWebSocket,closeWebSocket} from './websocket'; const Element=(param)=>{ useEffect(()=>{ let url="";//服务端连接的url createWebSocket(url) //在组件卸载的时候,关闭连接 return ()=>{ closeWebSocket(); } }) }
2.react 类组件中的使用
import {createWebSocket,closeWebSocket} from './websocket'; .... componentDidMount(){ let url="";//服务端连接的url createWebSocket(url) } componentWillUnmount(){ closeWebSocket(); } ....
如果一个连接,推送不同的消息如何处理?
1.需要安装 pubsub-js
2.修改webscocket.js 获取消息的代码
import { PubSub } from 'pubsub-js'; ... websocket.onmessage = function (event) { lockReconnect=true; //event 为服务端传输的消息,在这里可以处理 let data=JSON.parse(event.data);//把获取到的消息处理成字典,方便后期使用 PubSub.publish('message',data); //发布接收到的消息 'message' 为发布消息的名称,data 为发布的消息 } ...
3.在组件中的使用
函数组件中的使用(在类组件中类似)
import { PubSub } from 'pubsub-js'; useEffect(()=>{ //订阅 'message' 发布的发布的消息 messageSocket = PubSub.subscribe('message', function (topic,message) { //message 为接收到的消息 这里进行业务处理 }) //卸载组件 取消订阅 return ()=>{ PubSub.unsubscribe(messageSocket); } }
websocket在不同情形下的使用
1.在react中使用websocket
在项目根目录中创建一个websocket文件夹用于封装公用组件
代码如下:
/** * 参数:[socketOpen|socketClose|socketMessage|socketError] = func,[socket连接成功时触发|连接关闭|发送消息|连接错误] * timeout:连接超时时间 * @type {module.webSocket} */ class webSocket { constructor(param = {}) { this.param = param; this.reconnectCount = 0; this.socket = null; this.taskRemindInterval = null; this.isSucces=true; } connection = () => { let {socketUrl, timeout = 0} = this.param; // 检测当前浏览器是什么浏览器来决定用什么socket if ('WebSocket' in window) { console.log('WebSocket'); this.socket = new WebSocket(socketUrl); } else if ('MozWebSocket' in window) { console.log('MozWebSocket'); // this.socket = new MozWebSocket(socketUrl); } else { console.log('SockJS'); // this.socket = new SockJS(socketUrl); } this.socket.onopen = this.onopen; this.socket.onmessage = this.onmessage; this.socket.onclose = this.onclose; this.socket.onerror = this.onerror; this.socket.sendMessage = this.sendMessage; this.socket.closeSocket = this.closeSocket; // 检测返回的状态码 如果socket.readyState不等于1则连接失败,关闭连接 if(timeout) { let time = setTimeout(() => { if(this.socket && this.socket.readyState !== 1) { this.socket.close(); } clearInterval(time); }, timeout); } }; // 连接成功触发 onopen = () => { let {socketOpen} = this.param; this.isSucces=false //连接成功将标识符改为false socketOpen && socketOpen(); }; // 后端向前端推得数据 onmessage = (msg) => { let {socketMessage} = this.param; socketMessage && socketMessage(msg); // 打印出后端推得数据 console.log(msg); }; // 关闭连接触发 onclose = (e) => { this.isSucces=true //关闭将标识符改为true console.log('关闭socket收到的数据'); let {socketClose} = this.param; socketClose && socketClose(e); // 根据后端返回的状态码做操作 // 我的项目是当前页面打开两个或者以上,就把当前以打开的socket关闭 // 否则就20秒重连一次,直到重连成功为止 if(e.code=='4500'){ this.socket.close(); }else{ this.taskRemindInterval = setInterval(()=>{ if(this.isSucces){ this.connection(); }else{ clearInterval(this.taskRemindInterval) } },20000) } }; onerror = (e) => { // socket连接报错触发 let {socketError} = this.param; this.socket = null; socketError && socketError(e); }; sendMessage = (value) => { // 向后端发送数据 if(this.socket) { this.socket.send(JSON.stringify(value)); } }; }; export { webSocket, }
这样就完成了websocket的全局功能组件封装,在需要用的组件进行引用就行了
例:
import {webSocket} from "../../WebSocket/index"; //函数调用 WebSocketTest=()=>{ // 判断专家是否登录 let that = this; let userId = JSON.parse(localStorage.getItem("adminInfo")).id; console.log(userId) this.socket = new webSocket({ socketUrl: 'ws://xx.xxx.xxx/imserver/'+userId, timeout: 5000, socketMessage: (receive) => { console.log(receive) // if(receive.data === '1'){ // console.log(receive); //后端返回的数据,渲染页面 // }else if(JSON.parse(receive.data)){ // that.setState({msgData:receive.data}) // }else{ // message.info("有新消息了") // } try { if (typeof JSON.parse(receive.data) == "object") { that.setState({msgData:receive.data}) }else if(receive.data === '1'){ console.log(receive.data); } } catch(e) { message.info(receive.data) } }, socketClose: (msg) => { console.log(msg); }, socketError: () => { console.log(this.state.taskStage + '连接建立失败'); message.error("消息通信连接失败,建议刷新") }, socketOpen: () => { console.log('连接建立成功'); // 心跳机制 定时向后端发数据 this.taskRemindInterval = setInterval(() => { this.socket.sendMessage({ "msgType": 0 }) }, 30000) } }); //重试创建socket连接 try { this.socket.connection(); } catch (e) { // 捕获异常,防止js error // donothing } }
2.websocket在小程序中使用
小程序官方文档里是有相关的组件和调用方法,所以这里就不详细介绍了,简单说一下我的理解和使用方法。
在项目根目录下创建websocket文件
const app = getApp(); import { webSocketUrl } from '../utils/requst/url'; //websocket封装模块 const lqoWS = { openSocket(val) { let wsData = app.globalData.wsData; //我这里向后端传参用的路径参数,所以这里稍微设置一下 let urls = '' if(val == '/userSocket/'){ urls = webSocketUrl + val + wsData.id } if(val == '/ownerSocket/'){ urls = webSocketUrl + val + wsData.id + '/' + wsData.lon + '/' + wsData.lat; } //打开时的动作 wx.onSocketOpen(() => { console.log('WebSocket 已连接') app.globalData.socketStatus = 'connected'; this.sendMessage(val); }) //断开时的动作 wx.onSocketClose(() => { console.log('WebSocket 已断开') if(app.globalData.socketStatus == 'closeds'){ return } app.globalData.socketStatus = 'closed'; this.pdSocketOpen(val); }) //报错时的动作 wx.onSocketError(error => { console.error('socket error:', error) }) // 监听服务器推送的消息 wx.onSocketMessage(message => { //把JSONStr转为JSON message = message.data.replace(" ", ""); if (typeof message != 'object') { message = message.replace(/\ufeff/g, ""); //重点 var jj = JSON.parse(message); message = jj; } console.log(message) }) // 打开信道 wx.connectSocket({ url: urls, success:(res)=>{ console.log(res) } }) }, //关闭信道 closeSocket(val) { if (app.globalData.socketStatus == 'connected') { wx.closeSocket({ success: () => { app.globalData.socketStatus = 'closeds' } }) } }, //发送消息函数 sendMessage(val) { if (app.globalData.socketStatus == 'connected') { //自定义的发给后台识别的参数 ,我这里发送的是name wx.sendSocketMessage({ // data: "{\"name\":\"" + '123' + "\"}" data: app.globalData.wsData }) } }, pdSocketOpen (val) { setTimeout(() => { if(app.globalData.socketStatus == 'closed'){ // console.log(app.globalData.socketStatus) this.openSocket(val); } }, 4000) }, } export { lqoWS, }
使用
代码里的相关参数需要在全局中进行设置
import { lqoWS } from '../../websoket/index'; let val = '/ownerSocket/'; if(app.globalData.socketStatus == 'closed'){ // that.openSocket(); lqoWS.openSocket(val); } // lqoWS.closeSocket(val); lqoWS.sendMessage(val); lqoWS.pdSocketOpen(val);
小程序官方有非常详细的使用说明。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持阿兔在线工具。