使用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文件夹用于封装公用组件
代码如下:
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);
小程序官方有非常详细的使用说明。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。