websocket封装(含断网重连、支持同时建立多条连接、手动销毁)及vue项目中使用

1、新建websocket.js

/**
 * 发起websocket请求函数
 * @param {object} wsObj  - ws对象
*  @param {string} type  - 操作websocket:销毁close、创建create
*  @param {number} timeout  - 心跳间隔时长,默认5000ms
 * @param sendHeartBeat  - 以心跳,内容体区分string、object
 * @param {function} msgCallback  - 接收到ws数据,对数据进行处理的回调函数
 * @param {function} reCallback  - ws每次重连时,暴露对外的回调函数
 */
export function websocketCommand(wsObj,type,timeout=5000, sendHeartBeat, msgCallback, reCallback) {  
  let wsDestroy = type ==='close';  //  销毁标志
  let lockReconnect = false;  // 是否真正建立连接
  let timeoutObj = null;  // 心跳倒计时
  let serverTimeoutObj = null;  // 服务器心跳倒计时
  let timeoutnum = null;  // 断开 重连倒计时

  // 若type传入close,则意图销毁websocket
  if(type==='close'){
    clearTimeout(timeoutObj);
    clearTimeout(serverTimeoutObj);
    onClose();
  }
  // 若type传入create,则意图新建websocket,需初始化ws并发送心跳
  if(type==='create'){
    initWebsocket();
    websocketSend();  
  }

  function initWebsocket(){   
    if (typeof (WebSocket) === 'undefined') {
        console.log();('您的浏览器不支持WebSocket,无法获取数据');
        return false;
    }
    wsObj.onmessage = function (e) { onMessage(e) };
    wsObj.onopen = function () { onOpen() };
    wsObj.onerror = function () { onError() };
    wsObj.onclose = function () { onClose() } ;
  }

  function websocketSend () {
    // 加延迟是为了尽量让ws连接状态变为OPEN   
    setTimeout(() => { 
      // 添加状态判断,当为OPEN时,发送消息
      if (wsObj.readyState === wsObj.OPEN) { // wsObj.OPEN = 1 
        // console.log('类型',typeof sendHeartBeat);
        if( typeof sendHeartBeat == 'string'){
          // 若发送基本类型数据作为心跳,如字符串,直接将参数发送给服务端
          wsObj.send(sendHeartBeat)
        }else{
          // 若发送复杂类型数据作为心跳,如对象,则以回调方式暴露出去(得以支持动态数据)
          sendHeartBeat();
        }
      }
      // if (wsObj.readyState === wsObj.CLOSED) { // wsObj.CLOSED = 3 
      //   console.log('readyState=3')
      // }
    }, 500)
  }

  function onMessage(evt) {
    var received_msg = evt && JSON.parse(evt.data);
    msgCallback(received_msg);

    // 收到服务器信息, 重置服务器心跳
    start();
  }

  function onError() {
    console.log('ws_error');
    // 断网重连机制
    if(!wsDestroy){
      reconnect();
    }
  }

  function onOpen() {
    console.log("ws_open");
    // 连接成功向服务器发送信息,并开启心跳
    websocketSend();
    start();
  }

  function reconnect() {
    // 避免重复建立连接
    if (lockReconnect) { 
      return;
    }
    lockReconnect = true;
    // 没连接上会一直重连,设置延迟避免请求过多
    timeoutnum && clearTimeout(timeoutnum);
    timeoutnum = setTimeout(function() {
      // 重连
      initWebsocket();
      // 若重连后有需额外处理的逻辑,通过reCallback()回调暴露出去
      // reCallback?.();
      lockReconnect = false;
    }, timeout);
  }

  function start() {
   // 清计时器
    timeoutObj && clearTimeout(timeoutObj);
    serverTimeoutObj && clearTimeout(serverTimeoutObj);
    // 开启心跳
    timeoutObj = setTimeout(function() {
      if (wsObj.readyState == 1) {
        // 如果连接正常,发送心跳(服务端收到后会返回一条消息)
        websocketSend();
      } else {
        // 否则重连
        reconnect();
      }
      // 超时关闭
      serverTimeoutObj = setTimeout(function() {  
        wsObj.close();
      }, timeout);
    }, timeout);
  }

  function onClose() {
    if(!wsDestroy ){
      // 重连机制
      reconnect();
    }else if (wsObj.readyState == 1) {
      console.log('ws_close',wsObj);
     // 如果ws连接正常,则清计时器、断开连接
      clearTimeout(timeoutObj);
      clearTimeout(serverTimeoutObj);
      wsObj?.close?.();
    }
  } 
  
}


2、使用

  1. 引入:
import { websocketCommand } from '@/utils/websocket.js'

2.如vue项目,在methods中:

     //  ws连接成功,后台返回的ws数据
    receiveMsg (data) {
      console.log('服务端推送',data);
      // 收到服务端发送的数据后,需要处理的逻辑
      // 如:this.$store.dispatch("app/changeAppMsg",['receiveCloudMsg',data]);
    },
    // 建立连接、发起ws请求,以心跳方式,向服务端发送数据
    createWs () {
      this.wsObj = new WebSocket(process.env.VUE_APP_WEBSOCKET_API + '/ws/notification/v1/qpad?token=' + this.token);
      // 若为字符串类型,直接传参
      websocketCommand(this.wsObj, 'create', 1000, 'heartbeat');
      // 若为对象类型,以回调方式发送
      websocketCommand(this.wsObj, 'create', 5000, this.sendHeartBeat, this.receiveMsg,this.reconnectWs);
    },
    // 断网重连,需要处理的逻辑
    reconnectWs(){      
      if(this.wsObj){
        console.log('%c websocket_reconnect','color:blue');
        this.createWs();
        // todo
        // 如:this.$store.dispatch("app/changeAppMsg",['cloudWebsocketReconnect',true]);
      }
    },
    // 以回调方式向服务端发送(对象类型的)心跳
    sendHeartBeat(){
      console.log('发送心跳',this.sendObj);
      this.wsObj.send(JSON.stringify(this.sendObj));
    },
  1. 初始化调用(新建websocket):
this.createWs(); 
  1. 若需销毁websocket:
websocketCommand(this.wsObj,'close');
this.wsObj=null;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容