preface

Recently, the company has a project interface to use websocket way to obtain data and communication, inverted a simple encapsulation, for the introduction of Websocket and comparison of the advantages and disadvantages of HTTP can not be described here, nonsense not to say, on the code, look! (PS: Node server with available tests).

First, the client

1. Define webSocket (hereinafter referred to as WS), connection address, onMessage callback, onError callback, all in object format, supporting multiple WS connection at the same time

let ws = {};
let urlObj = {};
let messageCallback = {};
let errorCallback = {};
Copy the code

2. Define the methods that receive the data returned by the WS backend

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

3. Define WS to close the callback and delete the ws parameters

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

4. Initialize the WS connection

// initialize ws
function initWebsocket (key) {
  if (typeof (WebSocket) === 'undefined') {
    console.error('Your browser does not support WebSocket, cannot connect');
    return;
  }
  // The url that needs to be assembled can be assembled by itself
  // 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]}Connection error, please try again later);
    errorCallback[key]();
  };
  ws[key].onclose = function (e) {
    console.log(`${urlObj[key]} close----`);
    websocketOnClose(key, e);
  };
}
Copy the code

5. Ws sends a message when the initial connection succeeds

/ * * *@description: Initiates a WebSocket connection *@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 sends messages to the server
    sendMessage(key, params);
  } else if (ws[key].readyState === ws[key].CONNECTING) {
    // Not OPEN state, extend 1 second (self set) to call again
    setTimeout(() = > {
      websocketConllection(key, params);
    }, 1000);
  }
  if (ws[key].readyState === ws[key].CLOSED) {
    console.error(`${urlObj[key]}The connection is abnormal. Please try again later); errorCallback[key](); }}Copy the code

6. Create WS connection, create corresponding URL for each WS with URL as key, onMessage callback, onError callback

/ * * *@description: Adds the WS connection object *@author Arezy
 * @export
 * @param {Object}* {* URL, connect url * params = {}, convention parameter * onMessage, get service message callback * onError: error callback *} */
export function sendWebsocket ({ url, params = {}, onMessage, onError }) {
  urlObj[url] = url;
  messageCallback[url] = onMessage;
  errorCallback[url] = onError;
  initWebsocket(url);
  websocketConllection(url, params);
}
Copy the code

7. Define the method of sending messages and export total external calls

/ * * *@description: Sends messages *@author Arezy
 * @export
 * @param {String} key
 * @param {Object} Data and service convention parameter format */
export function sendMessage (key, data) {
  // The data sent to the back end needs to be stringed
  ws[key].send(JSON.stringify(data));
}
Copy the code

8. Define and close the corresponding WS connection method for external invocation

/ * * *@description: Close the WS connection *@author Arezy
 * @export* /
export function closeWebsocket (key) {
  if(ws[key]) { ws[key].close(); }}Copy the code

9. Full js

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

// Receive the data returned by the WS backend
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: Initiates a WebSocket connection *@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 sends messages to the server
    sendMessage(key, params);
  } else if (ws[key].readyState === ws[key].CONNECTING) {
    // Not OPEN state, extend 1 second (self set) to call again
    setTimeout(() = > {
      websocketConllection(key, params);
    }, 1000);
  }
  if (ws[key].readyState === ws[key].CLOSED) {
    console.error(`${urlObj[key]}The connection is abnormal. Please try again later); errorCallback[key](); }}// initialize ws
function initWebsocket (key) {
  if (typeof (WebSocket) === 'undefined') {
    console.error('Your browser does not support WebSocket, cannot connect');
    return;
  }
  // The url that needs to be assembled can be assembled by itself
  // 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]}Connection error, please try again later);
    errorCallback[key]();
  };
  ws[key].onclose = function (e) {
    console.log(`${urlObj[key]} close----`);
    websocketOnClose(key, e);
  };
}
/ * * *@description: Adds the WS connection object *@author Arezy
 * @export
 * @param {Object}* {* URL, connect url * params = {}, convention parameter * onMessage, get service message callback * onError: error callback *} */
export function sendWebsocket ({ url, params = {}, onMessage, onError }) {
  urlObj[url] = url;
  messageCallback[url] = onMessage;
  errorCallback[url] = onError;
  initWebsocket(url);
  websocketConllection(url, params);
}
/ * * *@description: Sends messages *@author Arezy
 * @export
 * @param {String} key
 * @param {Object} Data and service convention parameter format */
export function sendMessage (key, data) {
  // The data sent to the back end needs to be stringed
  ws[key].send(JSON.stringify(data));
}
/ * * *@description: Close the WS connection *@author Arezy
 * @export* /
export function closeWebsocket (key) {
  if(ws[key]) { ws[key].close(); }}Copy the code

10, called in Vue (available in any other framework),

The call is relatively simple, passing in the URL via sendWebsocket, the parameter params, the onMessage callback (to get the service data, which I printed directly here), the onError callback (to handle the exception), continuing communication via sendMessage, CloseWebsocket closes the WS connection (beforeDestroy hook function call, closes all connections to the current component) or manually

<! -- * @description: test webSocket * @author: Arezy * @Date: 2021-01-19 19:45:51
-->
<template>
  <div class="web-socket">
    <div class="btn"
      @click="sendMsg">Send message toUser</div>
    <div class="btn"
      @click="closeLogin">Close the userLogin</div>
    <div class="btn"
      @click="talking">Connect other Routes</div>
    <div class="btn"
      @click="sendTacking">Send messages to 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: {
    // Default initial ws connection
    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' });
    },
    // Create a second WS connection
    talking () {
      sendWebsocket({
        url: this.talkingUrl,
        params: { name: '西西'.context: 'Hello, Chettuzai.' },
        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: 'Fuck, I'm not cutting.' });
    }
  },
  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: 25px; }}</style>


Copy the code

2. Server (Node.js)

The server side is compact and is used only to test the WS connection; Modify the automatic restart service by using Express + Express-WS to construct the Nodemon detection

1. Index. js Uses Express Express-ws to start the service

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); // Set the listening port

var server = app.listen(app.get('port'), function () {
  console.log('Express server listening on port ' + server.address().port);
});
Copy the code

2. User.router. js supports BOTH WS and HTTP connections


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) {
      // Business code
      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) {
      // Business code
      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;
Copy the code

Node warehouse address (gitee) : https://gitee.com/ArezyLuo/node – ws – test NPM clone warehouse to pack the I NPM start to run the service

conclusion

When the Node service runs, you can test ws. Hope you can help those who need it