concept

  • WebSocket is a communication protocol that can be used over a single TCP connectionFull duplexCommunication. WebSocket makes it easier to exchange data between the client and the server, allowing the server to actively push data to the client. In the WebSocket API, the browser and server only need to complete a handshake to establish a persistent connection and two-way data transfer.
    • Full duplex: Term used for communication transmission. Communication allows data to be transmitted simultaneously in both directions. (A->b,b->A) (HTTP2.0)
    • Simplex: only party A is allowed to transmit information to Party B, and Party B cannot transmit information to Party A. (A->B, B ≠>A) (HTTP1.1 below)
    • Half duplex: Half duplex means that only one action occurs at a time. With the continuous progress of technology, the semi-double union gradually disappeared from the scene. A->B B can send A message to A after receiving A) (HTTP1.1)

An overview of the old HTTP architecture

HTTP 1.0 and HTTP 1.1

The HTTP 1.0

  • Earlier version 1.0 was a stateless, connectionless protocol. The browser and the server maintain a transient connection, and each request from the browser requires a TCP connection to the server.
    • No connection: The server disconnects the TCP connection immediately after the processing is complete. Each time a request is sent, it needs to go through the process of connection and release, which is quite time-consuming and makes the network utilization very low.
    • Stateless: The server does not track each client and does not record past requests. The benefit is that the server does not need to keep information about the session, but it also means that each request and response sends redundant information about the request.

The HTTP 1.1

  • For HTTP1.1, it not only inherits the simplicity of HTTP1.0, but also overcomes many performance problems of HTTP1.0.
    • HTTP 1.1 has been addedReusable connection, increasing theConnectionField by settingKeep-AliveYou can keep HTTP connections open. Reduce the number of connections from the customer side to the server side, reducing the latency of requests.
    • Request pipelining is supported by HTTP1.1. Although HTTP1.1 supports pipelining, the server must also send back responses one by one, which is a major drawback. In fact, browser vendors have taken a different approach, allowing multiple TCP sessions to open, which is the familiar browser limitation of loading 6 to 8 resources in the same domain in parallel.

HTTP polling, long polling, and streaming

polling

  • Polling is implemented by sending HTTP requests to the server at regular intervals. The server responds directly to the request regardless of whether there is data or not, and closes the TCP connection when the response is complete.
function Polling() { fetch(url).then(data => { // somthing }).catch(err => { console.log(err); }); } setInterval(polling, 5000);Copy the code

Long polling

  • Long polling is another popular method of communication where requests are kept open for a period of time until the client has available information or times out.
// Client function Polling() {fetch(url).then(data => {Polling()}).catch(err => {Polling() console.log(err); }); // router. Post ('./test',async ()=>{return new Promise(resolve =>{let time = new Date(); If (date.now () -time > 5000) {clearInterval(it); if (date.now () -time > 5000) {clearInterval(it); Resolve (' timeout '); Resolve (' resolve ')}, 10); }); })Copy the code

conclusion

  • The above approach provides near-real-time communication, which by then involves HTTP request and response headers, with a lot of additional and unnecessary header data and latency. Moreover, in each case, the client must wait for the request to return before making subsequent requests, adding to the delay.

Websocket is introduced

  • WebsocketIt is a natural full-duplex, single-socket connection. useWebSocket, your HTTP request becomes openWebSocketA single request for a connection, and reuse the same connection from customer side to server and server to customer side.
  • websocketReduced latency as once establishedwebsocketConnect, and the server can send messages as they become available. Unlike polling,websocketOnly one request is issued, and the server does not need to wait for a request from the customer side. Similarly, clients can send requests to the server at any time, greatly reducing latency compared to polling.

An overview of the Websocket API

introduce

  • The WebSocket API is an interface that enables applications to use the WebSocket protocol. You simply create a new instance of a Websocket object and provide the object with a URL representing the connection to be made.
// constructor const ws = new Websocket("ws://localhost:3333");Copy the code
  • There is also an optional parameter, protocols, that represents a subprotocol of WebSocket (which can also be a user-defined protocol) that can receive onestringorString array. Subprotocols allow webSocket protocol to support multiple data types (JSON,buffer,text..). Similar to HTTP requestsContent-Type: application/jsonHTTP types are MIME types, and HTTP types are MIME typesIETF RFC 6838Is defined and standardized in webSocket protocol, but there is no such specification in websocket protocol, need to use a sub-protocol to define.
  • The WebSocket protocol supports three types of local messages
    • 1. Text messages
    • Binary messages

    Blob objects are generally used to represent an immutable file object or raw data. This format is ideal if you don’t need to modify it or cut it up into smaller pieces. If you also need to reprocess the binary data you receive, ArrayBuffer is a better choice.

    • 3. Ping messages and Pong messages

      1) Two types of messages are commonly used to check the health of WebSocket connections (whether the connection is valid).

      2) The efficiency of WebSocket connection can be measured by measuring the time taken for Ping and Pong messages.

  • The WebSocket API is completely (truly) event-driven; once a full-duplex connection is established, there is no need to poll the server for the latest state, and the client simply listens for notifications and changes as needed.

Ws and WSS

  • The WebSocket protocol defines two URL schemes ———— WS and WSS, which are used for unencrypted and encrypted traffic between clients and servers respectively.
    • The default port of WS is 80, the unencrypted version, and anyone can connect as long as they know the IP and port number.
    • The default port of WSS is 433, the encrypted version, uses TLS for better security.

Schedule four different events for websocket

open

  • Once the server responds to a Webscoket connection, the open event fires and establishes a connection, with the corresponding callback functiononopen.
  • After the open event is triggered, you can determine that the Webscoket server successfully processed the connection request and agreed to communicate.

message

  • messageEvent is emitted when a message is received, and the corresponding callback function isonmessage.
  • In addition to text messages, Websockets can also handle binary data as wellBlobThe message orArrayBufferThe message

error

– Error Events are triggered when responding to unexpected faults. The corresponding callback event is onError. If you receive an error event, you can expect a close event to be raised shortly.

close

  • closeEvent raised when the WebSocket connection is closed. The corresponding callback functiononcloseOnce the connection is closed, the client and server can no longer receive or send messages.
  • There are three useful attributes in the close event that you can use to analyze the cause of the disconnect.
    • Wasclean: is a Boolean value indicating whether the connection closed successfully. Returns true for a close frame from the server. Abnormal closing returns false.
    • Code Indicates the disconnected identifier
    • Reason Indicates the reason for the disconnection
  • Code and reason are the same as code and reason passed in websocket.close(code,reason).

Two methods of websocket

send()

  • Can be called after the open event listening for the WebSocket is completesend()Methods.
// Const ws = new Websocket(' ://test.com') ws. Send ('hello') // correct ws. Onopen = ()=>{ws.Copy the code
  • If used elsewheresend()Method can be checkedWebsocket.readyStateProperty and select only inWebsocket.readyState===1
  • ReadyState: Records the status of the connection
    • 0: CONNECTING – Indicates that a connection is not established
    • 1: OPEN: the connection is established
    • 2: CLOSING — The connection is CLOSING
    • 3: CLOSED — The connection is CLOSED or unavailable

close()

  • Using the close method, you can close a WebSocket connection or connection attempt. After calling close, data cannot be sent.
  • The close method takes two arguments,codeStatus code andreasonCloses the cause string.

bufferedAmount

  • websocket.bufferedAmountIs a read-only property that returns the number of bytes of data that have been queued by the send() method but not yet sent to the network.
  • If it is turned off during sending, the property value is not reset to 0 and will continue to grow as send() is called.

  • You can judgewebsocket.bufferedAmount===0It can also be used to obtain the amount of unsent data in the queue to control the rate of sending data.
const ws = new Websocket('ws://test.com') ws.onopen = ()=>{ setInterval(()=>{ if(ws.bufferedAmount<1024*10){ Ws. send(' send more messages than 10K ')}},1000)}Copy the code

protocol

  • websocket.protocolRepresents the protocol used on websocket and is a read-only property.protocolThe feature is not empty before the initial handshake is complete, if the server does not select a protocol provided by the clientprotocolKeep the value null.

Webscoket agreement

Webscoket initial handshake

  • Each WebSocket connection begins with an HTTP request, similar to any other request, but containing a special request headerUpgrade.UpgradeThe request header indicates that the client is upgrading the connection to a different protocol.
Upgrade: websocket
Copy the code

Webscoket response headers

  • The response must contain a 101 status code,Upgrade.Sec-Websocket-AcceptOtherwise, the WebSocket connection cannot succeed.Sec-Websocket-AcceptThe value of the response header fromSec-Websocket-KeyIs inherited from.
// node.js // count sec-websocket-accept const crypto = require('crypto'); // KEY_SUFFIX is a fixed key suffix contained in a protocol specification const KEY_SUFFIX = "258eafa5-e914-47DA-95ca-C5AB0dc85b11 "; Const hashWebSocketKey = (key) => {// createHash function const sha1 = crypto.createhash (' sha1 '); // Update the hash to the specified key sha1.update(key + KEY_SUFFIX); Return sha1.digest("base64"); }Copy the code

Websocket is different from HTTP

  • inHTTP1.0One request, one response and the HTTP link ends. And in theHTTP1.1Improved links, addedkeep-alive, that is, in an HTTP request, there can be multiple requests and responses, but only request -> response, each response is passive, can not actively send information to the client. Websocket solves the passivity of HTTP links and can actively send information to clients.

Websocket security problem

Cross-domain request

Problem description

  • When initiating a Websocket handshake, the browser adds a name namedOriginThe webSocket specification does not enforce a handshake phaseOriginRequest header, andSec-WebSocket-KeyIt is automatically generated by the browser. If the user is tricked into visiting a malicious web page, and the malicious web page implanted a section of JS code, then the user will automatically bringCookieAnd other authentication parameters, malicious web pages can successfully bypass the identity authentication to connect to the WebSocket server, and then steal the information sent by the server, or send forged information to the server to tamper with the server data.

To solve

  • 1. Server pairOriginIf the Origin message sent by the client comes from a different domain, the server can reject the request.
  • 2. You can learn from the CSRF solution and generate it before shaking handstokenWear it when you shake handstoken, the server to verifytoken(The generated token is unique and random).

Denial of service

The client

  • The WebSocket connection limit is different from the HTTP connection limit. WebSocket has a higher connection limit than HTTP. Different browsers have their own specific maximum number of connections (IE maximum 6, Chrome maximum 255). Using up all allowed Websocket connections deplets browser resources, causing denial of service.

The service side

  • An attacker can apply for a large number ofwebsocketPersistent connections deplete server resources. To counter this attack, you can limit the maximum number of connections per IP address.
  • An attacker can send a single massive data stream to drain server memory and trigger denial of service. To prevent this attack, you can limit the total message size.

Input validation

  • WebSocket applications, like traditional Web applications, need to verify input to defend against XSS attacks on the client, SQL injection on the server, and code injection attacks.

conclusion

  • websocketIt’s a new protocol based on TCP,websocketIt has great performance advantages, but does not solve the security problems existing in traditional Web applications, which needs to be understood by developerswebscoketSecurity problems, and how to prevent and avoid these security problems.

Websokcet Heartbeat reconnection

  • websocketIt is a long connection between the front and back ends. Both the front and back ends may fail because of some circumstances and there is no feedback between them. So in order to make the connection sustainable and stable,websocketReconnection of the heart was born.
  • If you’re usingwebscoketWhen the network is suddenly disconnected, websocket will not trigger any events, only the next timesend()“, the browser will notice that the connection has been disconnected, will trigger in a short timeoncloseEvent (different browsers trigger at different times). The back endwebsocketIt is also possible for the service to raise an exception that disconnects the connection, but the front end is not notified. Therefore, the front-end timing is requiredpingThe message is received by the back endpingReturn immediately after the messagepongThe message. If the front end does not receive as expectedpongMessage indicating an abnormal connection triggers a reconnection operation.
// index.html ... <script> function initWebsocket (){ const ws = new Webscoket('ws://localhost:8888'); let timeoutCount; const beatTime = 10000; Ws.onopen = function(){timeoutCount = setTimeout(function(){ws.send('HeartBeat')},beatTime); } ws.onMessage =function(){// Clear the timer when the message is received and restart the heartbeat clearTimeout(timeoutCount); Heartbeart ()} ws.onclose = function () {heartbeart()} ws.onclose = function () { InitWebsocket () can then be reconnected; }; } initWebsocket(); </script> ...Copy the code

Create a simple chat room

  • Create a simple chat room to showcase webSocket’s broadcast capabilities
  • The front-end code
// index.html <! DOCTYPE html> <html lang="en"> <body> <div style="height: 700px;" > <div id="chat" style="height: 300px;" </div> <input ID ="name" /> <input ID ="message" /> <button onclick="sendMessage()"> Send </button> </div> <script> const ws = new WebSocket('ws://localhost:8080'); Function appendLog(nickname, message) {const messages = document.getelementbyid ('chat'); const messageElem = document.createElement("li"); Messageem. innerHTML = '${nickname} : ${message}'; messages.appendChild(messageElem); } function sendMessage() {const messageField = document.getelementByid ('message'); const nameField = document.getElementById('name'); If (namefield.value === "){alert(' Please enter a name '); return } if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ name: nameField.value, message: messageField.value })); } messageField.value = ''; messageField.focus(); } ws.onmessage = function (e) { const data = JSON.parse(e.data); appendLog(data.name, data.message); } </script> </body> </html>Copy the code
  • The node code
// index.js const ws = require('ws').Server; const wss = new WebSocketServer({ port: 8080 }); Var clients = []; Function broadcastSend(name, message) {clients. ForEach (function (v, i) { if (v.ws.readyState === ws.OPEN) { v.ws.send(JSON.stringify({ name, message })); }})} / / listening WSS. On (' connection ', function (ws) {clients. Push ({" ws ": the ws,}); Parse (message) {const data = JSON. Parse (message); console.log('data',data); broadcastSend(data.name, data.message); }); })Copy the code

Reference article:

  • The definitive guide to HTML5 WebSocket
  • Analysis of WebSocket application security problems