美文网首页
vue websocket 的使用(聊天)

vue websocket 的使用(聊天)

作者: FM_0138 | 来源:发表于2023-12-11 13:58 被阅读0次

    因为h5中提供了websocket模块, 所以我们可以直接使用, 不需要使用其他三方库, 为了方便管理websocket的各种状态, 及消息的发送接受, 我们可以单独创建一个js文件来管理.

    vue前段代码

    创建websocketManager.js文件

    // 定义websocket 地址
    let socketurl = "ws://192.168.0.252:8091";
    // 重连锁, 防止过多重连
    let reconnectLock = false;
    // 定义一个消息发送中(包含发送失败的)的字典
    window.messageSendingDic = {};
    // 定义一个消息websocket连接状态的字段, 并且要绑定到widow上, 方便调用
    // 0 未连接, 1 连接成功 2 连接中
    window.webSocketState = 0;
    
    // 定义连接服务器方法
    function connectWebsocket(){
        //如果用户已登录, 进行连接websoket, 如果没有登陆, 登录后进行连接 用token判断
        // 创建一个websocket连接
        // let webSocket = new WebSocket(socketurl);
        
        // 如果想要传token, 因为ws不支持通过设置header, 所以直接在地址中加参数, 
        // 如ws://192.168.0.252:8091?name=lulu&token=123456
        let name = "lulu";
        let token = "1234"
        let webSocket = new WebSocket(socketurl+`?appname=${name}&token=${token}`);
        // 监听webSocket的各个状态
        // 连接成功
        webSocket.onopen = function() {
            console.log("websocket连接成功")
            // 连接成功后将连接状态改变
            window.webSocketState = 1;
            // 连接成功后, 要将消息队列里面的消息重新发送出去(底层重发, 和页面无关)
            for(let session in window.messageSendingDic){
                session.forEach(message => {
                    // 重发消息
                    reSendMessage(message)
                });
           }
        }
        // 连接出错
        webSocket.onerror = function(error){
            console.log("websocket连接出错", error);
            // 进行重连
            reconnectWebsocket();
        }
        // 连接关闭
        webSocket.onclose = function(result){
            console.log("websocket连接关闭", result);
            if(result == "退出登录"){
                return
            }
            // 进行重连
            reconnectWebsocket();
        }
        // 接受到消息
        webSocket.onmessage = function(message){
            console.log("websocket接受到消息", message);
            // 将受到的消息进行分类, 分发处理
            formatAcceptMessage(message)
        } 
        // 将webSocket绑定到window上面, 方便后续调用
        window.webSocket = webSocket;
    }
    
    // 定义重连方法 如果连接失败, 或者关闭, 
    function reconnectWebsocket(){
        // 如果正在重连, 则返回
        if(reconnectLock){
            return;
        }
        // 进行加锁
        reconnectLock = true;
        // 重连时将连接状态改变
        window.webSocketState = 2;
        // 为了防止过多请求, 1s后进行重连
        setTimeout(function(){
            // 解锁
            reconnectLock = false;
            // 进行连接, 如果失败接着重连
            // connectWebsocket();
        }, 1000)
    
    }
    /**
     * 关闭websocket 退出时会用到
     *
     */
    function closeWebsocket(){
        window.webSocket.onclose("退出登录")
    }
    // 定义发送消息的方法 message 格式为json
    /**
     * 
     * @param {
     *      message: "内容",
     *      id: "xxxxxxx"
     * } message 消息内容
     * @param "1" messageType 消息类型
     * @param "QueryMsg" messageClass 附加字段吗消息类, 这里是以protobufjs的消息类为例
     */
    function sendMessage(message, messageType, messageClass) {
        // 这里可以对message做一些格式化处理
        let formaterMessge = message;
    
        // 将消息添加到发送中的数组中进行记录
        // 先判断该回话有没有对应的数组, 如果没有就创建, 在添加, 如果有直接添加
        if(window.messageSendingDic[message.sessionId]) {
            window.messageSendingDic[message.sessionId].push(formaterMessge);
        } else {
            window.messageSendingDic[message.sessionId] = [];
            window.messageSendingDic[message.sessionId].push(formaterMessge);
        }
        // 如果websocket连接成功, 进行发送消息
        if(window.webSocketState == 1) {
            formaterMessge = JSON.stringify(formaterMessge)
            // 这里就可以直接用window调用了
            window.webSocket.send(formaterMessge);
        } else {
            // 如果websocket没有连接成功, 直接告诉消息发送页面消息发送失败, 模拟接受到消息, 发给对应页面
            let formaterMessge = {};
            // 将处理后的消息进行发送通知, 通知给需要的页面进行处理, 在需要的页面进行监听 
            // 注意: 使用页面添加window.addEventListener("acceptNewMessage", this.testAction)
            window.dispatchEvent(new CustomEvent("acceptNewMessage", formaterMessge));
        }
    }
    
    // 定义重发送消息的方法 message 格式为json
    /**
     * 
     * @param {
    *      message: "内容",
    *      id: "xxxxxxx"
    * } message 消息内容
    * @param "1" messageType 消息类型
    * @param "QueryMsg" messageClass 附加字段吗消息类, 这里是以protobufjs的消息类为例
    */
    function reSendMessage(message) {
       // 如果websocket连接成功, 进行发送消息
       if(window.webSocketState == 1) {
           // 这里就可以直接用window调用了
           window.webSocket.send(message);
       } 
    }
    
    // 定义收到消息进行消息解析的方法
    function formatAcceptMessage(message) {
        // 处理消息. 格式化
        let formaterMessge = message;
        // 将发送成功的消息从发送中移除
        if(window.messageSendingDic[message.sessionId]) {
            let sendingArray = window.messageSendingDic[message.sessionId];
            // 过滤发送成功的
            window.messageSendingDic[message.sessionId] = sendingArray.filter(msg => {
                return msg.id != message.id
            });
        } 
        // 将处理后的消息进行发送通知, 通知给需要的页面进行处理, 在需要的页面进行监听 
        // 注意: 使用页面添加window.addEventListener("acceptNewMessage", this.testAction)
        window.dispatchEvent(new CustomEvent("acceptNewMessage", formaterMessge));
    }
    
    // 如果服务器端有消息确认, 可以根据消息确认, 添加消息是否发送成功的状态, 
    // 需要单独创建一个数组, 用来存放发送中的数据(包含发送失败的数据)
    
    
    module.exports = {
        connectWebsocket,
        sendMessage
    }
    

    在main.js中引入

    import {connectWebsocket} from "@/manager/webSocketManager";
    //如果用户已登录, 进行连接websoket, 如果没有登陆, 登录后进行连接
    if(token){
      connectWebsocket();
    }
    
    

    会话页面chat.vue

    import {sendMessage} from "@/manager/webSocketManager"
    clickSendButton(){
      console.log("点击了发送消息")
      sendMessage({
           sessionId: "1234567890",
           userId: this.name,
           messageId: "100000",
           message: {
                 type: "text",
                 content: this.message
           },
                    
       })
    },
    

    注意: websocket默认如果长时间发消息, 会断开(服务器设置websocket永远不断开除外), 所以需要设置心跳包进行websocket保活.

    退出账号是要关闭socket , 主动退出要处理重连问题

    // 退出登录
      logout (ctx) {
       // 主动关闭连接
        websocket.onclose("退出登录")
        Message.success('退出成功,请重新登录')
      }
    

    node 后台代码

    node 不能直接使用websocket,需要安装支持websocket的包
    这里使用的三方库nodejs-websocketws或者socket.io
    安装

    npm install nodejs-websocket
    或
    npm I ws
    或者
    npm install socket.io
    

    在主页面加入以下代码

    const ws = require("nodejs-websocket");
    //定义一个对象,用于存放正在连接中的socket, 字段名是以token命名
    const conningObjet = {};
    
    let webServe = ws.createServer(function (connection) { 
      // console.log('创建成功', connection)
      //连接成功的回调
      
      // 获取连接的token
      let path = connection.path;
      let pathParams = getParamsFromURL(path);
      console.log(pathParams);
      // 不满足服务器条件时服务器主动断开连接
      if(pathParams.token) {
        // 如果token正确进行继续操作
        //如果是第一次连接, 添加到对应的数组, 如果不是, 不用继续添加
        if (!conningObjet[pathParams.token]) { 
          //将用户发来的信息对所有用户发一遍
          conningObjet[pathParams.token] = connection;
        }
        //监听数据,当客户端传来数据时的操作
        connection.on("text", function (result) {
          console.log('接受到消息', result)
          // console.log(result)
          console.log(conningObjet.keys)
          //数据只能是以字符串或buffer形式传递,所以这里要转换成JSON;
          var data = JSON.parse(result); 
          // 收到消息后立即向服务器端发送确认消息
          // 确认消息添加确认消息类型, 1 表示确认消息
          data.type = "1";
          connection.sendText(JSON.stringify(data))
        })
        connection.on('connect', function(code) {
          console.log('开启连接', code)
    
        })
        connection.on('close', function(code, reason) {
          console.log('关闭连接', code)
          console.log('关闭原因:', reason)
          console.log(conningObjet);
          // 获取连接的token
          let path = connection.path;
          let pathParams = getParamsFromURL(path);
          console.log(pathParams.token);
          // 连接关闭时要将这个连接从连接对象中移除
          delete conningObjet[pathParams.token]
          console.log(conningObjet);
        })
        connection.on('error', function(code) {
          console.log('异常关闭', code)
        })
      } else {
        // 如果token 不合理就进行断开
        connection.close(1, "token不正确");
      }
      
    });
    webServe.listen(8091);
    webServe.on('connection', connection => {
      console.log("游客户端进行连接");
      
    })
    
    // 获取url上的参数, 使用的是正则表达式
    function getParamsFromURL(url) {
      const regex = /[?&]([^=#]+)=([^&#]*)/g;
      const params = {};
      let match;
      while (match = regex.exec(url)) {
        params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
      }
      return params;
    }
    

    相关文章

      网友评论

          本文标题:vue websocket 的使用(聊天)

          本文链接:https://www.haomeiwen.com/subject/cphrgdtx.html