react使用websocket实时通信方式

2022-09-15 15:16:38

目录使用websocket实时通信创建公共组件在react组件中的使用websocket在不同情形下的使用1.在react中使用websocket2.websocket在小程序中使用使用websock...

目录
使用websocket实时通信
创建公共组件
在react组件中的使用
websocket在不同情形下的使用
1.在react中使用websocket
2.websocket在小程序中使用

使用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 js= 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);

小程序官方有非常详细的使用说明。 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。