Vue2.0+WebSocket对接示例

简言

项目需要对接长链,客户端与服务端保持会话,以便客服及时查看需要审核的内容。所以此功能我们师徒二人来共同来研究完成。

操作

第一步:封装WebSocket.js文件

首先需要创建websocket文件,方便后续多次调用,下面是连接和检查心跳的方法:

// websocket实例

let wsObj = null;

// ws连接地址

let wsUrl = null;

// let userId = null;

// 是否执行重连 true/不执行 ; false/执行

let lockReconnect = false;

// 重连定时器

let wsCreateHandler = null;

// 连接成功,执行回调函数

let messageCallback = null;

// 连接失败,执行回调函数

let errorCallback = null;

// 发送给后台的数据

let sendDatas = {};

 

 

/**

 * 发起websocket请求函数

 * @param {string} url ws连接地址

 * @param {Object} agentData 传给后台的参数

 * @param {function} successCallback 接收到ws数据,对数据进行处理的回调函数

 * @param {function} errCallback ws连接错误的回调函数

 */

export const connectWebsocket = (url, agentData, successCallback, errCallback) => {

  wsUrl = url;

  createWebSoket();

  messageCallback = successCallback;

  errorCallback = errCallback;

  sendDatas = agentData;

}

 

// 手动关闭websocket (这里手动关闭会执行onclose事件)

export const closeWebsocket = () => {

  if (wsObj) {

    writeToScreen('手动关闭websocket');

    wsObj.close() // 关闭websocket

    // wsObj.onclose() // 关闭websocket(如果上面的关闭不生效就加上这一条)

    // 关闭重连

    lockReconnect = true;

    wsCreateHandler && clearTimeout(wsCreateHandler);

    // 关闭心跳检查

    heartCheck.stop();

  }

}

 

// 创建ws函数

const createWebSoket = () => {

  if (typeof (WebSocket) === 'undefined') {

    writeToScreen("您的浏览器不支持WebSocket,无法获取数据");

    return false

  }

  // const host = window.location.host;

  // userId = GetQueryString("userId");

  // wsUrl = "ws://" + host + "/websoket" + userId;

 

  try {

    wsObj = new WebSocket(wsUrl);

    initWsEventHandle();

  } catch (e) {

    writeToScreen("连接异常,开始重连");

    reconnect();

  }

}

 

const initWsEventHandle = () => {

  try {

    // 连接成功

    wsObj.onopen = (event) => {

      onWsOpen(event);

      heartCheck.start();

    }

 

    // 监听服务器端返回的信息

    wsObj.onmessage = (event) => {

      onWsMessage(event);

      heartCheck.start();

    }

 

    wsObj.onclose = (event) => {

      writeToScreen('onclose执行关闭事件');

      onWsClose(event);

    }

 

    wsObj.onerror = (event) => {

      writeToScreen('onerror执行error事件,开始重连');

      onWsError(event);

      reconnect();

    }

  } catch (err) {

    writeToScreen('绑定事件没有成功,开始重连');

    reconnect();

  }

}

 

const onWsOpen = (event) => {

  writeToScreen('CONNECT');

  // // 客户端与服务器端通信

  // wsObj.send('我发送消息给服务端');

  // 添加状态判断,当为OPEN时,发送消息

  if (wsObj.readyState === wsObj.OPEN) { // wsObj.OPEN = 1 

    // 发给后端的数据需要字符串化

    wsObj.send(JSON.stringify(sendDatas));

  }

  if (wsObj.readyState === wsObj.CLOSED) { // wsObj.CLOSED = 3 

    writeToScreen('wsObj.readyState=3, ws连接异常,开始重连');

    reconnect();

    errorCallback(event);

  }

}

const onWsMessage = (event) => {

  const jsonStr = event.data;

  writeToScreen('onWsMessage接收到服务器的数据: ', jsonStr);

  messageCallback(jsonStr);

}

const onWsClose = (event) => {

  writeToScreen('DISCONNECT');

  // e.code === 1000  表示正常关闭。 无论为何目的而创建, 该链接都已成功完成任务。

  // e.code !== 1000  表示非正常关闭。

  console.log('onclose event: ', event)

  if (event && event.code !== 1000) {

    writeToScreen('非正常关闭');

    errorCallback(event);

    // 如果不是手动关闭,这里的重连会执行;如果调用了手动关闭函数,这里重连不会执行

    reconnect();

  }

}

const onWsError = (event) => {

  writeToScreen('onWsError: ', event.data);

  errorCallback(event);

}

 

const writeToScreen = (massage) => {

  console.log(massage);

}

 

// 重连函数

const reconnect = () => {

  if (lockReconnect) {

    return;

  }

  writeToScreen('3秒后重连');

  lockReconnect = true;

  // 没连接上会一直重连,设置延迟避免请求过多

  wsCreateHandler && clearTimeout(wsCreateHandler);

  wsCreateHandler = setTimeout(() => {

    writeToScreen('重连...' + wsUrl);

    createWebSoket();

    lockReconnect = false;

    writeToScreen('重连完成');

  }, 3000);

}

 

// 从浏览器地址中获取对应参数

const GetQueryString = (name) => {

  let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");

  // 获取url中 ? 符后的字符串并正则匹配

  let r = window.location.search.substr(1).match(reg);

  let context = "";

  r && (context = r[2]);

  reg = null;

  r = null;

  return context;

}

 

 

// 心跳检查(看看websocket是否还在正常连接中)

let heartCheck = {

  timeout: 15000,

  timeoutObj: null,

  serverTimeoutObj: null,

  // 重启

  reset() {

    clearTimeout(this.timeoutObj);

    clearTimeout(this.serverTimeoutObj);

    this.start();

  },

  // 停止

  stop() {

    clearTimeout(this.timeoutObj);

    clearTimeout(this.serverTimeoutObj);

  },

  // 开启定时器

  start() {

    this.timeoutObj && clearTimeout(this.timeoutObj);

    this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);

    // 15s之内如果没有收到后台的消息,则认为是连接断开了,需要重连

    this.timeoutObj = setTimeout(() => {

      writeToScreen("心跳检查,发送ping到后台");

      try {

        const datas = { ping: true };

        wsObj.send(JSON.stringify(datas));

      } catch (err) {

        writeToScreen("发送ping异常");

      }

      console.log("内嵌定时器this.serverTimeoutObj: ", this.serverTimeoutObj)

      // 内嵌定时器

      this.serverTimeoutObj = setTimeout(() => {

        writeToScreen("没有收到后台的数据,重新连接");

        reconnect();

      }, this.timeout)

    }, this.timeout)

  }

}

在src的utils目录中新建文件:ws.js,并将上述代码复制进去。

第二步:在vue中局部调用

// 此处需要注意路径,用相对路径即可
//connectWebsocket(建立长链接的方法)、closeWebsocket(关闭长链接方法)

import { connectWebsocket, closeWebsocket } from '../utils/ws'

如果在main.js中加载上述代码,则是全局调用

第三步:建立链接,接收数据

connectWebsocket(

      // 测试地址

      'ws://127.0.0.1:9901/client/1',

      // 传递给后台的数据

      { openexe: 'openexe' },

      // 成功拿到后台返回的数据的回调函数

      (data) => {

          // 在此可以接收到来自服务器的成功调用记录,但是需要判断好需要处理的参数,因为此方法会频繁调用,包括监测心跳💓包也会走此方法,所以需要特殊注意。根据第一步封装的ws.js文件中的设置,心跳监测周期为15秒。

        console.log('成功的回调函数, 接收到的data数据: ', data)

      },

      // websocket连接失败的回调函数

      (err) => {

        console.log('失败的回调函数', err)

      }

)

总结

整个过程比较简单,不需要加载其他的npm组件;

需要注意的点:

  • 第三步的成功方法中的data为string格式,需要转换成json使用。
(data) => {

      // 在此可以接收到来自服务器的成功调用记录,但是需要判断好需要处理的参数,因为此方法会频繁调用,包括监测心跳💓包也会走此方法,所以需要特殊注意。根据第一步封装的ws.js文件中的设置,心跳监测周期为15秒。
    //将data转换成json格式
    data = JSON.parse(data);
    console.log('成功的回调函数, 接收到的data数据: ', data)

  },
  • closeWebsocket是关闭长链接方法,备注方便后续查看。
  • websocket协议头为ws,区别于http,需要注意使用!
© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容