前端js封装一个聊天的websocket连接

今天我们来封装一下websocket的连接

首先我们新建一个js文件叫chatWs.js,下面是js的内容

// chatWs.js
import { Message } from "element-ui";
const STATE = {
  HEART: "heartbeat",
  LOGIN: "connection",
  LOGOUT: "disconnection",
  RECEIVED_MSG_RESULT: "receivedMsgResult",  //收到消息给一个响应
  MSG_RES: 'newMsg',         // 新消息通知
}
// 导出一个类
export class chatWs {
  constructor(){
    this.jsocket = null;        // 与 CTI 服务器,建立一个 websocket 对象
    this.wsUrl = '';
    this.reconnectTime = 6000;        // 重新连接间隔时间值
    this.keepaliveTime = 6000;        // 保持连接间隔时间值
    this.reconnectInterval = null;        // 重新连接定时器
    this.heartInterval = null;      // 心跳定时器
    this.headInterval = null;          // 计算心跳是否还在的定时器
    this.reconnected = false;      // 是否是重连
    this.isConnected = false;    // 是否已经连接
    this.callBack = {};      // 回调

    this.domainConfig = {};               // webscoket的域名等配置项
    this.sendMsgList = [];  // 发送过的心跳消息集合

    this.activeCloseWs = false; // 是否主动断开连接

    this.userName = "";


    this.msgSendResultTimer = {};   //消息发送是否成功定时器
    this.msgSendResultTimmOutTime = 5000;  // 消息发出之后未收到响应就认定发送失败的时间

  }
  init(config,cb){
    if(!config.domainConfig){
      let obj = {
        code: 0,
        message: '请先填写配置项'
      }
      this.errorMsgCallback(obj);
    }
    this.callBack = Object.assign({},cb);
    this.domainConfig = config.domainConfig;
    this.userName = config.userName;
    if(!this.domainConfig.protocol)this.domainConfig.protocol = "ws";

    this.wsUrl = this.domainConfig.isDomain ? `${this.domainConfig.protocol}://${config.domainConfig.domain}${config.domainConfig.suffix ? config.domainConfig.suffix : "" }` : `${config.domainConfig.protocol}://${this.domainConfig.domain}:${this.domainConfig.port}${config.domainConfig.suffix ? config.domainConfig.suffix : ""}`;
    this.connectWs();
  }
  connectWs(){
    if(this.jsocket)this.jsocket.close();
    try{
       this.jsocket = new WebSocket(this.wsUrl);
    } catch (e){
      this.jsocket = null;
      this.errorMsgCallback({message: `连接${this.wsUrl}有误`});
      return;
    }
    this.jsocket.onopen = (msg) => {   // ws已经连接
      this.wsOpen(msg);
    }
    this.jsocket.onmessage = (msg) => {
      this.wsMessages(msg.data);
    }
    this.jsocket.onerror =  (msg) => {
      this.wsError(msg);
    }
    this.jsocket.onclose = (msg) => {
      this.wsClose(msg);
    }

  }
  wsOpen(msg){
    this.isConnected = true;
    this.activeCloseWs = false;
    if(this.reconnectInterval)clearTimeout(this.reconnectInterval);
    this.login();
  }
  wsMessages(msg){
    try{
     msg = JSON.parse(msg);
    }catch(err) {
      return;
    }
    if(msg.event !== STATE.HEART)this.receivedMsgResult(msg);
    switch(msg.event){
      case STATE.HEART:
        const index = this.sendMsgList.findIndex(v => v.msgId === msg.msgId);
        if(index > -1)this.sendMsgList.splice(index,1);
        break
      case STATE.LOGIN:  // 登录成功发送心跳
        this.sendHeart();
        if(this.callBack.onLogin)this.callBack.onLogin(msg);
        break
      case STATE.LOGOUT:  // 退出登录
        if(this.callBack.onLogout)this.callBack.onLogout();
        this.beforClose();
        if(this.jsocket)this.jsocket.close();
        break;
      case STATE.MSG_RES:  // 收到聊天消息
        if(this.callBack.receviedMsg)this.callBack.receviedMsg(msg);
        break;      

      default :
       break
    }
  }
  wsError(msg){
    console.log('连接出错');

    let obj = {
      code : 0,
      message: `连接${this.wsUrl}失败,请联系运维人员处理`
    }
    if(this.callBack.connectError)this.callBack.connectError(obj);

    this.errorMsgCallback(obj);
    this.beforClose();
    if(!this.activeCloseWs)this.reConnectWs();//不是主动断开连接才发起重连
  }
  wsClose(msg){
    console.log('ws close');
    if(this.callBack.onLogout)this.callBack.onLogout();
    this.beforClose();

  }


  reConnectWs(){
    this.beforClose();
    if(this.reconnectInterval)clearTimeout(this.reconnectInterval);
    this.reconnected = true;
    // this.connectWs();
    this.reconnectInterval = setTimeout(()=> {
      this.reconnected = true;
      this.connectWs();
    }, this.reconnectTime)
  }
  beforClose(){
    if(this.heartInterval)clearInterval(this.heartInterval);
    if(this.headInterval)clearInterval(this.headInterval);
    this.isConnected = false;

  }
  closeWs(){
    if(this.reconnectInterval)clearTimeout(this.reconnectInterval);
    if(this.jsocket)this.jsocket.close();
    this.activeCloseWs = true;

  }
  errorMsgCallback(err){
    Message({
      message: err.message ? err.message : '失败',
      type: 'error'
    });
  }
  sendMsg(msg){
    if(!this.isConnected){
      let obj = {
        code: -1,
        message: "ws未连接"
      }
      this.errorMsgCallback(obj);
      return;
    }
    const msgId = this.uuid(32,16)
    let publicObj = {
      msgId: msgId,
      timestamp: new Date().getTime(),
      userName: this.userName
    }
    let obj = Object.assign(publicObj,msg);
    if(obj.event && obj.event === STATE.HEART) this.sendMsgList.push(obj);
    const str = JSON.stringify(obj);
    this.jsocket.send(str);
  }
  // 收到消息之后给一个收到的回应
  receivedMsgResult(row){
    const obj = {
      event : STATE.RECEIVED_MSG_RESULT,
      msgId: row.msgId,
    }
    this.sendMsg(obj);
  }
  sendHeart(){
    if(this.heartInterval)clearInterval(this.heartInterval);
    if(this.headInterval)clearInterval(this.headInterval);
    let obj = {
      event: STATE.HEART,
    }
    this.sendMsg(obj);
     //发送心跳包
    this.heartInterval = setInterval(() => {
      let obj = {
        event: STATE.HEART,
      }
      this.sendMsg(obj);

    }, this.keepaliveTime);

    this.headInterval = setInterval(() => {
      // 两次心跳没有响应间隔在三十秒之内
      if(this.sendMsgList.length > 2
        &&  (this.sendMsgList[this.sendMsgList.length - 1].timestamp - this.sendMsgList[this.sendMsgList.length - 2].timestamp) / 1000 > 30
         && (this.sendMsgList[this.sendMsgList.length - 1].timestamp - this.sendMsgList[this.sendMsgList.length - 3].timestamp) / 1000 > 30 ){
        let data =  {
          code: -11,
          message: '超过30秒没有心跳,需要重新登录.'
        }
        this.errorMsgCallback(data);
        this.beforClose();
        this.jsocket.close();

        setTimeout(()=>{
          Message({
            message: '将在6s之后进行重连',
            type: 'info'
          });
           // 10秒之后进行重连
          setTimeout(()=>{
            this.reConnectWs()
          }, 6000)

        },4000)
       

      }


    }, 10000);


  }

  login(){
    let obj = {
      event : STATE.LOGIN,
      isReConnection: this.reconnected ? 1 : 0,
      token: sessionStorage.token,
      type: 1,
    }
    this.sendMsg(obj);
  }
  uuid (len,radix) {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
      .split('');
    var uuid = [], i;
    radix = radix || chars.length;

    if (len) {
      // Compact form
      for (i = 0; i < len; i++)
        uuid[i] = chars[0 | Math.random() * radix];
    } else {
      // rfc4122, version 4 form
      var r;

      // rfc4122 requires these characters
      uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
      uuid[14] = '4';

      // Fill in random data.  At i==19 set the high bits of clock sequence as
      // per rfc4122, sec. 4.1.5
      for (i = 0; i < 36; i++) {
        if (!uuid[i]) {
          r = 0 | Math.random() * 16;
          uuid[i] = chars[(i === 19) ? (r & 0x3) | 0x8 : r];
        }
      }
    }
    return uuid.join('');
  }

}


调用方式

// xxx.vue中
<script>
import {chatWs} from './chatWs.js';
export default {
	  data (){
	    this.chatWs = new chatWs();
	    return {
	    
	    }
	  },
	  computed:{
	   callBack(){
      	return {
      	 receviedMsg:(obj)=>{
      	 // 收到消息的回调函数   do someing····
      	 }
      	}
      }	
	  },

 mounted(){
    this.initWs();
  },
  beforeDestroy(){
    console.log('page beforeDestroy');
    this.chatWs.beforClose();
    this.chatWs.closeWs();
  },
  methods:{
  	initWs(){
	    let config = {
	        domainConfig:{
	          domain: 127.0.0.1,  // ip或者域名
	          port: 8866,  // 端口
	          protocol: location.protocol === 'https:' ? 'wss' : 'ws',
	          suffix:'/api/websocket',// 可要可不要,具体看根据后端的ws地址来决定
	          isDomain: 0, // ws地址是否需要端口  0-需要(本地调试是ip地址需要端口)  1-不需要(线上域名不需要端口)
	       
	        },
	        userName: sessionStorage.user ? JSON.parse(sessionStorage.user).email : '',  // 连接ws的用户名
	
	      }
	      this.chatWs.init(config, this.callBack);   // 发起ws连接
	      }
	   }
	  
 }

 </script>

我们可以使用 JavaScript 中的 `WebSocket` 对象来创建一个 WebSocket 连接,然后封装一些常用的方法来简化操作。以下是一个简单的封装示例: ```javascript class WebSocketClient { constructor(url) { this.url = url; this.websocket = null; this.isConnected = false; this.connect(); } connect() { this.websocket = new WebSocket(this.url); this.websocket.onopen = () => { this.isConnected = true; console.log('WebSocket 连接成功'); }; this.websocket.onmessage = (event) => { console.log('收到消息:', event.data); }; this.websocket.onclose = () => { this.isConnected = false; console.log('WebSocket 连接关闭'); }; this.websocket.onerror = (error) => { console.error('WebSocket 错误:', error); }; } send(message) { if (this.isConnected) { this.websocket.send(message); console.log('发送消息:', message); } else { console.error('WebSocket 连接未建立'); } } close() { if (this.isConnected) { this.websocket.close(); console.log('WebSocket 连接关闭'); } else { console.error('WebSocket 连接未建立'); } } } ``` 使用示例: ```javascript const ws = new WebSocketClient('ws://localhost:8080'); ws.send('Hello, WebSocket!'); ws.close(); ``` 在上面的示例中,我们使用 `WebSocketClient` 类来封装一个 WebSocket 客户端,提供了 `connect`、`send` 和 `close` 方法。其中,`connect` 方法用于建立 WebSocket 连接,`send` 方法用于发送消息,`close` 方法用于关闭连接。在创建实例时,会自动调用 `connect` 方法来建立连接
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值