最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • websocket简易封装,附node测试服务

    正文概述 掘金(泛黄的枫叶)   2021-01-26   573

    前言

    最近公司有项目接口要使用websocket的方式获取数据和通讯,倒腾了个简易封装,对于websocket的介绍及对比http的优劣势这里不做赘述可自行百度,废话不多说,上code,淦!(PS:附带可用测试的node服务端)。

    一,客户端

    1.定义websocket(后面简称ws),连接地址,onMessage回调,onError回调,均为对象格式,支持多个ws同时连接

    let ws = {};
    let urlObj = {};
    let messageCallback = {};
    let errorCallback = {};
    

    2.定义接收ws后端返回的数据方法

    function websocketOnMessage (key, e) {
      messageCallback[key](JSON.parse(e.data));
    }
    

    3.定义ws关闭回调,删除对应的ws参数

    function websocketOnClose (key, e) {
      if (!ws[key]) return;
      delete ws[key];
      delete urlObj[key];
      delete messageCallback[key];
      delete errorCallback[key];
    }
    

    4.初始化ws连接

    // 初始化ws
    function initWebsocket (key) {
      if (typeof (WebSocket) === 'undefined') {
        console.error('您的浏览器不支持WebSocket,无法连接');
        return;
      }
      // 需要组装url 可自行组装
      // http: ws:xx, https: wss:xxx
      ws[key] = new WebSocket(urlObj[key]);
      ws[key].onopen = function () {
        console.log(`${urlObj[key]} open-----`);
      };
      ws[key].onmessage = function (e) {
        websocketOnMessage(key, e);
      };
      ws[key].onerror = function () {
        console.error(`${urlObj[key]} 连接出错,请稍候重试`);
        errorCallback[key]();
      };
      ws[key].onclose = function (e) {
        console.log(`${urlObj[key]} close----`);
        websocketOnClose(key, e);
      };
    }
    

    5.ws初始连接成功时发送消息

    /**
     * @description:发起websocket连接
     * @author Arezy
     * @param {String} key
     * @param {Object} params
     * @returns
     */
    function websocketConllection (key, params) {
      if (!ws[key]) return;
      if (ws[key].readyState === ws[key].OPEN) {
        // OPEN状态发送消息给服务端
        sendMessage(key, params);
      } else if (ws[key].readyState === ws[key].CONNECTING) {
        // 非OPEN状态,延长1秒(自行设置)重新调用
        setTimeout(() => {
          websocketConllection(key, params);
        }, 1000);
      }
      if (ws[key].readyState === ws[key].CLOSED) {
        console.error(`${urlObj[key]} 连接异常,请稍候重试`);
        errorCallback[key]();
      }
    }
    

    6.创建ws连接,以url为key 为每个ws创建对应的url,onMessage回调,onError回调

    /**
     * @description: 添加ws连接对象
     * @author Arezy
     * @export
     * @param {Object}
     * {
     *  url, 连接url
     *  params = {}, 约定参数
     *  onMessage, 获取服务消息回调
     *  onError: 出错回调
     *  }
     */
    export function sendWebsocket ({ url, params = {}, onMessage, onError }) {
      urlObj[url] = url;
      messageCallback[url] = onMessage;
      errorCallback[url] = onError;
      initWebsocket(url);
      websocketConllection(url, params);
    }
    

    7.定义发送消息的方法,导出共外部调用

    /**
     * @description: 发送消息
     * @author Arezy
     * @export
     * @param {String} key
     * @param {Object} data 和服务约定参数格式
     */
    export function sendMessage (key, data) {
      // 发给后端的数据需要字符串化
      ws[key].send(JSON.stringify(data));
    }
    

    8.定义关闭对应ws连接方法,供外部调用

    /**
     * @description: 关闭ws连接
     * @author Arezy
     * @export
     */
    export function closeWebsocket (key) {
      if (ws[key]) {
        ws[key].close();
      }
    }
    

    9.完整版js

    let ws = {};
    let urlObj = {};
    let messageCallback = {};
    let errorCallback = {};
    
    // 接收ws后端返回的数据
    function websocketOnMessage (key, e) {
      messageCallback[key](JSON.parse(e.data));
    }
    
    function websocketOnClose (key, e) {
      if (!ws[key]) return;
      delete ws[key];
      delete urlObj[key];
      delete messageCallback[key];
      delete errorCallback[key];
    }
    /**
     * @description:发起websocket连接
     * @author Arezy
     * @param {String} key
     * @param {Object} params
     * @returns
     */
    function websocketConllection (key, params) {
      if (!ws[key]) return;
      if (ws[key].readyState === ws[key].OPEN) {
        // OPEN状态发送消息给服务端
        sendMessage(key, params);
      } else if (ws[key].readyState === ws[key].CONNECTING) {
        // 非OPEN状态,延长1秒(自行设置)重新调用
        setTimeout(() => {
          websocketConllection(key, params);
        }, 1000);
      }
      if (ws[key].readyState === ws[key].CLOSED) {
        console.error(`${urlObj[key]} 连接异常,请稍候重试`);
        errorCallback[key]();
      }
    }
    // 初始化ws
    function initWebsocket (key) {
      if (typeof (WebSocket) === 'undefined') {
        console.error('您的浏览器不支持WebSocket,无法连接');
        return;
      }
      // 需要组装url 可自行组装
      // http: ws:xx, https: wss:xxx
      ws[key] = new WebSocket(urlObj[key]);
      ws[key].onopen = function () {
        console.log(`${urlObj[key]} open-----`);
      };
      ws[key].onmessage = function (e) {
        websocketOnMessage(key, e);
      };
      ws[key].onerror = function () {
        console.error(`${urlObj[key]} 连接出错,请稍候重试`);
        errorCallback[key]();
      };
      ws[key].onclose = function (e) {
        console.log(`${urlObj[key]} close----`);
        websocketOnClose(key, e);
      };
    }
    /**
     * @description: 添加ws连接对象
     * @author Arezy
     * @export
     * @param {Object}
     * {
     *  url, 连接url
     *  params = {}, 约定参数
     *  onMessage, 获取服务消息回调
     *  onError: 出错回调
     *  }
     */
    export function sendWebsocket ({ url, params = {}, onMessage, onError }) {
      urlObj[url] = url;
      messageCallback[url] = onMessage;
      errorCallback[url] = onError;
      initWebsocket(url);
      websocketConllection(url, params);
    }
    /**
     * @description: 发送消息
     * @author Arezy
     * @export
     * @param {String} key
     * @param {Object} data 和服务约定参数格式
     */
    export function sendMessage (key, data) {
      // 发给后端的数据需要字符串化
      ws[key].send(JSON.stringify(data));
    }
    /**
     * @description: 关闭ws连接
     * @author Arezy
     * @export
     */
    export function closeWebsocket (key) {
      if (ws[key]) {
        ws[key].close();
      }
    }
    
    

    10,在Vue中调用(可在其他任意框架中使用),

    调用比较简单,通过sendWebsocket 传入url,参数params,onMessage回调(获取服务数据,笔者这里直接打印出来了), onError回调(处理异常),通过sendMessage 持续通讯,closeWebsocket关闭ws连接(beforeDestroy钩子函数调用,关闭当前组件所有连接),也可手动关闭

    <!--
     * @Description: 测试webSocket
     * @Author: Arezy
     * @Date: 2021-01-19 19:45:51
    -->
    <template>
      <div class="web-socket">
        <div class="btn"
          @click="sendMsg">发送消息toUser</div>
        <div class="btn"
          @click="closeLogin">关闭userLogin</div>
        <div class="btn"
          @click="talking">连接其他路由</div>
        <div class="btn"
          @click="sendTacking">发送消息到talking</div>
      </div>
    </template>
    
    <script>
    import { sendWebsocket, closeWebsocket, sendMessage } from '../../utils/socket.service.js';
    export default {
      'name': 'Websocket',
      data () {
        return {
          url: 'ws:localhost:3000/user/login?token=123456789',
          talkingUrl: 'ws:localhost:3000/user/talking/usid001'
        };
      },
      created () {
        this.init();
      },
      methods: {
        // 默认初始第一个ws连接
        init () {
          sendWebsocket({
            url: this.url,
            params: { name: 'lily' },
            onMessage: this.message,
            onError: this.onError
          });
        },
        message (data) {
          console.log('login ws message: ', data);
        },
        onError () {
          console.log('login ws error');
        },
        closeLogin () {
          closeWebsocket(this.url);
        },
        sendMsg () {
          sendMessage(this.url, { name: 'Tony' });
        },
        // 创建第二个ws连接
        talking () {
          sendWebsocket({
            url: this.talkingUrl,
            params: { name: '西西', context: '你好啊,切图仔' },
            onMessage: this.cMessage,
            onError: this.conError
          });
        },
        cMessage (data) {
          console.log('talking ws message: ', data);
        },
        conError () {
          console.log('talking ws error');
        },
        sendTacking () {
          sendMessage(this.talkingUrl, { name: '西西', context: '淦,我不切图了' });
        }
      },
      beforeDestroy () {
        closeWebsocket(this.url);
        closeWebsocket(this.talkingUrl);
      }
    };
    </script>
    
    <style lang="less" scoped>
    .web-socket {
      position: relative;
      width: 100%;
      margin-left: 50px;
      .btn {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 150px;
        padding: 5px 15px;
        background: #2f7dcd;
        color: #ffffff;
        border-radius: 5px;
        margin-top: 0.5rem;
      }
    }
    </style>
    
    
    

    二,服务端(node.js)

    服务端很简洁,只用来测试ws连接;
    以express + express-ws构建
    nodemon检测修改自动重启服务

    1.index.js 使用express express-ws启动服务

    var express = require('express');
    var expressWs = require('express-ws');
    var userRouter = require('./router/user.router.js');
    
    var app = express();
    expressWs(app);
    app.use('/user', userRouter);
    
    app.set('port', process.env.PORT || 3000); // 设定监听端口
    
    var server = app.listen(app.get('port'), function () {
      console.log('Express server listening on port ' + server.address().port);
    });
    

    2.user.router.js 支持ws连接 和 http连接

    
    var express = require('express');
    var expressWs = require('express-ws');
    
    var router = express.Router();
    expressWs(router);
    
    router
      .ws('/login', function (ws, req) {
        ws.on('message', function (msg) {
          // 业务代码
          const name = JSON.parse(msg).name;
          const resp = {
            token: req.query.token,
            name: name,
            message: `${name} login`
          };
          console.log('login msg req: ', resp);
          ws.send(JSON.stringify(resp));
        });
      })
      .get('/login', function (req, res) {
        console.log("? ~ file: user.router.js ~ line 21 ~ req", req.query)
        res.send(req.query);
      })
      .post('/login', function (req, res) {
      });
    
    router
      .ws('/talking/:usessionId', function (ws, req) {
        console.log("? ~ file: user.router.js ~ line 34 ~ req", req.query)
        console.log("? ~ file: user.router.js ~ line 34 ~ req", req.params);
        ws.on('message', function (msg) {
          // 业务代码
          const { context = '', name = '' } = JSON.parse(msg);
          const resp = {
            name: name,
            message: `${name} talking ${context}`
          };
          console.log('talking msg req: ', resp);
          ws.send(JSON.stringify(resp));
        });
      })
    
    module.exports = router;
    

    node仓库地址(gitee):https://gitee.com/ArezyLuo/node--ws-test
    clone仓库 npm i 装包 npm start即可运行服务

    总结

    node服务跑起来,即可测试ws,希望可以帮到需要的小伙伴~


    起源地下载网 » websocket简易封装,附node测试服务

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元