Two practices on Websocket (Vue project realizes online chat & Angular project pushes chart data in real time on the home page)

Posted by SithLordKyle on Mon, 17 Jan 2022 02:36:14 +0100

Abstract: This article records my two practical experiences in using websocket. In the first practice, I stepped on a lot of holes. The second practice is handy, but many theories are still lacking. Through this article, from theory to practice, we won it all in one fell swoop.

catalogue

1, Websocket theory

(1) What is Websocket?

(2) What is the background of Websocket?

(3) Advantages of adopting the protocol?

(4) Handshake protocol

(5) What is the difference between Websocket and Socket?

(6) About socket io

2, Vue enables online chat (practice and stepping on the pit)

3, Real time push chart data on the front page of Angular project

1, Websocket theory

(1) What is Websocket?

Websocket is a network communication protocol, which is a full duplex communication protocol on a single TCP connection.

WebSocket makes the data exchange between the client and the server easier, and allows the server to actively push data to the client. In the WebSocket API, the browser and server only need to complete a handshake, and they can directly create a persistent connection and conduct two-way data transmission.

Full duplex communication: also known as two-way simultaneous communication, that is, both sides of the communication can send and receive information at the same time.

As for the classification of communication protocols, the article is illustrated and introduced in detail: https://blog.csdn.net/Dingjiawang6/article/details/81093518

(2) What is the background of Websocket?

Many websites in order to achieve Push technology , the technologies used are polling . Polling is sent by the browser to the server at a specific time interval (such as every 1 second) HTTP request Then, the server returns the latest data to the client's browser. This traditional mode brings obvious disadvantages, that is, the browser needs to constantly send requests to the server, but HTTP requests may contain a long time head , the really effective data may be only a small part. Obviously, this will waste a lot of bandwidth and other resources.

The effect of polling with relatively new technologies is Comet . Although this technology can communicate two-way, it still needs to make repeated requests. Moreover, in Comet, the long link commonly used will also consume server resources.

under these circumstances, HTML5 WebSocket protocol is defined, which can better save server resources and bandwidth, and communicate in real time.

(3) Advantages of adopting the protocol?

  • Less control overhead. After the connection is created, when data is exchanged between the server and the client, the packet header for protocol control is relatively small. Without extensions, this header size is only 2 to 10 for server to client content byte (related to packet length); For client to server content, this header needs to be added with an additional 4 bytes Mask . This overhead is significantly reduced compared to the fact that HTTP requests carry a complete header every time.

  • More real-time. Because the protocol is full duplex, the server can actively send data to the client at any time. Compared with the HTTP request, the server needs to wait for the client to initiate the request before responding, and the delay is significantly less; Even compared with long polling similar to Comet, it can transfer data more times in a short time.

  • Keep connected. Different from HTTP, Websocket needs to create a connection first, which makes it a stateful protocol. After that, some state information can be omitted during communication. HTTP requests may need to carry status information (such as identity authentication) in each request.

  • Better binary support. Websocket defines Binary Frames, compared with HTTP, can handle binary content more easily.

  • Can support extension. Websocket defines extensions. Users can extend the protocol and implement some custom sub protocols. For example, some browsers support compress Wait.

  • Better compression. be relative to HTTP Compression , Websocket can follow the previous content with appropriate extension support context , the compression ratio can be significantly improved when transmitting similar data.

(4) Handshake protocol

WebSocket is also an application layer protocol like HTTP, but it is a two-way communication protocol based on TCP.

Websocket pass HTTP /1.1 handshake with the 101 status code of the protocol.

In order to create a Websocket connection, you need to send a request through the browser and then the server responds. This process is usually called“ handshake"(handshaking).

Handshake process:

1. The browser and server establish a TCP connection and shake hands three times. This is the basis of communication. If the transmission control layer fails, it will not be executed later.
2. After the TCP connection is successful, the browser transmits the version number and other information supported by WebSocket to the server through HTTP protocol. (HTTP handshake before start)
3. After receiving the handshake request from the client, the server also uses the HTTP protocol to feed back the data.
4. After receiving the message of successful connection, transmit communication through TCP channel.

(5) What is the difference between Websocket and Socket?

Socket is the API of TCP and IP network. It is a layer abstracted for the convenience of using TCP or UDP. It is a group of interfaces between application layer and transport layer, and Websocket is a typical application layer protocol.

(6) About socket io

Socket.IO is node JS, which is a simple way to communicate through WebSocket. The WebSocket protocol is very complex. It will take a lot of time to write an application that supports WebSocket from scratch. Socket.IO provides both server and client components, so only one module is needed to add WebSocket support to the application. Socket.IO also solves the support problem of each browser (not all browsers support WebSocket) and enables real-time communication across almost all commonly used browsers. Socket. The design of IO is very good, and the process of bringing real-time communication into the application is very simple. If you want to do anything that involves communicating between the web server and the browser, nodejs and socket IO is a great choice!

# npm install socket op
$ npm install --save socket.io

2, Vue enables online chat (practice and stepping on the pit)

Requirements: add the online chat function between after-sales service personnel and customers in the background management system.

Frame: Vue

Step 1: connect websocket and carry token

The methods of connecting websocket include native methods. The code is as follows:

`initWebSocket () {
    // Initialize websocket
    const wsuri = 'wss://XXXXXXXXXXXXXX/ws/adminOnlineService'
    this.websock = new WebSocket(wsuri)
},`

Step 1: for my project, an error of 500 is reported for this connection because the token is not carried. What I know about the way to carry the token is as follows:
(1) Send send parameter. The disadvantage of this method is that each time a message is sent, the websocket will be reconnected;
(2) The request address contains parameters, such as var. wss = new WebSocket("wss://" + url?token + "/webSocketServer");
(3) Based on protocol header: this websock = new WebSocket(wsuri, ['Bearer' + store.state.token]);
After some attempts, I think that no matter which method is adopted, we need to negotiate with the server, that is, what type is transmitted from the front end and the corresponding processing method should be adopted at the back end. Don't easily deny any method. This is an attempt process. This is because the front end has tried many ways and finally decided to put it in the request address. At this time, the server does the corresponding processing.
Another way to connect to websocket is to use socket io-client

`onConnect: () => {
      console.log('connect')
      this.message = 'connect'
    },
    onDisconnect: () => {
      console.log('disconnect')
      this.message = 'disconnect'
    },
    connect: () => {
      let socket = io('wss://XXXXXXXXXXX', {
        path: '/welfare/ws/adminOnlineService',
        query: {
          'Authorization': 'Bearer  abdadfssadfasdf'
        }
      })
      socket.connect()
}`

In this way, the token will be brought when the request is made, but the same token will be spelled in the url, which needs further processing by the server. The connection is successful in this way, but the problem is that after the connection is successful, it will be disconnected, and then it will be connected immediately. This cycle will continue until the page is refreshed. The problem was not solved at that time. However, this problem does not exist in the native mode. You can connect it once.

Practice step 2: connect to websocket when you click the login button

Click the login button to connect to websocket. It is required to define the global method. vuex was used at that time. Although time has passed for a long time, and it seems that this scheme does not need to be adopted now, let's review the implementation ideas at that time.

Create a new websocket under the modules of vuex JS file, where the code is as follows:

import store from './user'
const state = {
  websock: null
}

const mutations = {
  STAFF_UPDATEWEBSOCKET (state, websock) {
    state.websock = websock
  }
  // STAFF_SEND (state, text) {
  //   state.websock.send(text)
  // }
}

// To realize the connection of websocket, you need to carry the parameter token
const actions = {
  // The parameter deconstruction of ES2015 is used to simplify the code (especially when we need to call commit many times)
  STAFF_WEBSOCKET ({ commit }) {
    let token = encodeURI('Bearer ' + store.state.token)
    const wsuri = 'wss://XXXXXXXXX/?Authorization=' + token + '&EIO=3&transport=websocket'
    commit('STAFF_UPDATEWEBSOCKET', new WebSocket(wsuri))
    // Only when the onopen method is defined can we continue to receive messages, that is, call the onmessage method where it is used.
    state.websock.onopen = function () {
    }
    // Heartbeat packet. There is no data in about 30s. The browser will disconnect heartbeat
    setInterval(function () {
      state.websock.send(JSON.stringify({
        'heart': true
      }))
    }, 30000)
  }
}

// This part is to obtain the related methods of websocket. You will find that the writing here is similar to that in mutations. However, if you want to use return, you need to write the relevant data in getters.
const getters = {
  STAFF_UPDATE (state) {
    return state.websock
  }
}
export default {
  state,
  mutations,
  actions,
  getters
}

Relevant code comments have been reflected in the above code, and the use method is in the following code:

1. Call the send method of websocket, that is, when you click send, the send method will be called to send the message to the server. The following code adopts different methods for different definition methods. For example, the third method is to obtain the information in getters; The second method is to get the staff of the comments in the changes_ Methods in send; The first is to get the method defined in actions.

At first glance, it seems superfluous. Isn't it more convenient for us to distribute mutation directly? In fact, this is not the case. Remember that mutation must execute this restriction synchronously? Action is not constrained! We can perform asynchronous operations inside the action

// Action through store Dispatch method trigger
this.$store.dispatch('STAFF_WEBSOCKET')
// this.$store.commit('STAFF_SEND').send('This is a message from the client ')
this.$store.getters.STAFF_UPDATE.send('sdfsfs')

Actions supports the same load mode and object mode for distribution:

// Distribute as load
store.dispatch('incrementAsync', {
  amount: 10
})

// Distribute as objects
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

 2. Receive messages from the server through websocket. The implementation method is as follows:

onmessage () {
  let that = this
  this.$store.getters.STAFF_UPDATE.onmessage = function (evt) {
  let message = JSON.parse(evt.data)
  that.messages.push({
     content: message.content,
     self: false
  })
 }
}

The key is to get the onmessage method from getters. As emphasized above, you need to implement the onopen method before calling this method.

As above, chat can be realized.

Practice step 3: events and methods of websocket

//Instantiate a WebSocket object and pass in the decision URL to connect
var socket = new WebSocket("url");//    Use ws: / / in the url instead of http: / /; Use wss instead of https://
//The open event is triggered when the connection is successfully established
socket.onopen = function(){
    alert("established");
}
//The error event is triggered when an error occurs
socket.onerror = function(){
    alert("error!");
}
//The close event is triggered when the connection is closed
socket.onclose = function(){
    alert("closed!");
}
//Using the send() method to send data can only accept strings. json objects should be serialized into json strings first
socket.send(str);
//When the server sends a message to the client, the WebSocket object will trigger the message event
socket.onmessage = function(event){
    console.log(event.data);//The returned data is also in string form
}
//Calling the close() method closes the Web Sockets connection. You can call the close() method at any time
 socket.close();

3, Real time push chart data on the front page of Angular project

In the above background of the emergence of Websocket, this paper introduces the reasons for the emergence of Websocket. In fact, this is also the reason why the demand uses the scheme in the project. In other projects contacted, the page will also be refreshed in real time, and nearly 10 interfaces will be requested after a period of time. In this demand, there are more data and more request interfaces, so this method is adopted.

The following is the implementation code. In fact, the use process is the same, mainly depending on the business logic.

initWebSocket() {
    const url = '*******';
    const ws = new WebSocket(url);

    ws.onopen = () => {
      this.clearWS();
      this.ws = ws;
      ws.onmessage = evt => {
        // The following is the business logic
        const data = JSON.parse(evt.data);
        if (this.simpleMode) {
          this.reciveFromWs4Simple(data);
        } else {
          this.reciveFromWs(data);
        }
      };
      ws.onclose = () => {
        this.clearWS();
      };
      ws.onerror = () => {
        this.clearWS();
      };
    };
  }
   /**
   * Clear references, events
   */
  private clearWS() {
    const ws: WebSocket = this.ws;
    if (ws) {
      ws.onclose = null;
      ws.onopen = null;
      ws.onmessage = null;
    }
    this.ws = null;
  }
  /**
   * Change to the logic of heartbeat monitoring whether the connection is disconnected Check every 10 seconds
   */
  private heartbeat() {
    this.reConnectTimer = window.setInterval(() => {
      const ws: WebSocket | null = this.ws;
      if (!this.isWSAvailable(ws)) {
        this.reConnect();
      }
    }, 10000);
  }
   /**
   * Make a reconnection, and make a pseudo reconnection with close and error
   */
  private reConnect() {
    console.warn('reconnect');
    this.clearWS();
    this.initWebSocket();
  }
sendByWs(data) {
    const ws = this.ws;
    if (!ws) {
      console.warn('[ws-Failed to send data]: Websocket Not ready or disconnected');
      return;
    }

    switch (ws.readyState) {
      case WebSocket.CONNECTING:
        console.warn('[ws-Failed to send data]: Websocket Connecting...');
        break;
      case WebSocket.OPEN:
        ws.send(JSON.stringify(data));
        break;
      default:
        console.warn('[ws-Failed to send data]: Websocket About to disconnect or already disconnected');
    }
  }

  switchLive(live) {
    this.live = live;
    const name = 'live';
    this.sendByWs({ name, live });
  }
ngOnDestroy() {
    this.ws && this.ws.close(1000, 'The user has left the current page or the page has been refreshed');
    this.reConnectTimer && clearInterval(this.reConnectTimer);
  }

Topics: Javascript angular websocket