WebSocket introduction, examples and records of problems encountered in development

WebSocket knowledge sharing

Premise introduction

What is WebSocket

webSocket is a network communication protocol. The difference between webSocket and Htpp protocol is that Htpp communication can only be initiated by the client and responded by the server; The biggest feature of webSocket is that the server can actively push information to the client, and the client can also actively send information to the server to realize two-way communication between the client and the server.

WebSocket API

  • WebSocket. Callback for successful onopen connection
  • WebSocket. Callback after onclose connection is closed
  • WebSocket. Callback after onerror connection failure
  • WebSocket. The onmessage client receives the callback of the server data
  • WebSocket.readyState current connection state
  • WebSocket.bufferedAmount is the number of binary bytes not sent to the server
  • WebSocket.binaryType uses binary data type connections
  • WebSocket. Subordinate protocols selected by the protocol server
  • WebSocket. URL absolute path to websocket

method

  • WebSocket.close() closes the current connection
  • WebSocket.send(data) sends data to the server

Other features

  • The handshake phase adopts HTTP protocol
  • Lightweight data format and low performance overhead
  • Text, and binary data can be sent
  • There is no restriction of homology policy
  • The identifier of webSocket protocol is ws, and wss is encrypted
    The identifier of http protocol is http, and https is encrypted

Several methods of real-time communication with server

In addition to WebSocket, there are other ways to establish real-time communication with the server

  • AJAX polling
  • Long Polling

Front end code (no complicated ws is used according to the requirements, and the native ws connection is used)

// Initialize ws and establish a connection with the server
var url = 'ws://localhost:8080/rest/openingController/websocket'
var websocket = null
//Determine whether the browser supports WebSocket
if ('WebSocket' in window) {
    websocket = new WebSocket(url);
} else if ('MozWebSocket' in window) {
    websocket = new MozWebSocket(url);
} else {
    websocket = new SockJS(url); // SockJS third party Library
}

// Initialize ws method
websocket.onopen = onOpen;
websocket.onmessage = onMessage;
websocket.onerror = onError;
websocket.onclose = onClose;
function onOpen(result) {
    console.log('Triggered when the connection is established')
	heartBeatCheck.start(); // After the connection is established successfully, start heartbeat detection
}
function onMessage(result) {
    console.log('Triggered when the client receives data from the server')
}
function onError(result) {
    console.log('Triggered when a communication error occurs');
}
function onClose(result) {
    console.log('Triggered when the connection is closed');
}
function doSend(params) {
    websocket.send(params);
	console.log('The client sends data to the server')
}

//Handle websocket business
var ifCheckHeart = true; //Whether to enable heartbeat detection

//websocket heartbeat detection
var heartBeatCheck = {
	timeout: 5000,
	timeoutObj: null,
	serverTimeoutObj: null,
	start: function start() {
		if (!ifCheckHeart) {
			return false;
		}

		clearTimeout(heartBeatCheck.timeoutObj);
		clearTimeout(heartBeatCheck.serverTimeoutObj);

		heartBeatCheck.timeoutObj = setTimeout(function () {
			websocket.send("client heart beat check");//A heartbeat is sent here. After receiving it, the backend returns a heartbeat message,
			heartBeatCheck.serverTimeoutObj = setTimeout(function () {
			   websocket.onClose();
			}, heartBeatCheck.timeout);
		}, heartBeatCheck.timeout);
	}
}

// Disconnect when closing the web page. In fact, when leaving the web page again, it will be automatically disconnected because it can no longer be detected
window.onbeforeunload = function () {
     websocket.onClose();
};

Difficult problems encountered in development

Here are two problems encountered in development. You can refer to similar problems later, because I think this kind of problem is a common problem

Question 1

Problem phenomenon:

After entering the page for a few seconds, the pop-up connection is disconnected

Cause of problem:

It is normal to establish ws in Google, ie and 360 security browsers, but in Apple browsers 13 and 14, ws has been established successfully. However, because Apple browser does not support the original protocol of ws, the connection is disconnected after the connection is established successfully. The error code is 1006
(Note: this problem occurs not only in Apple browsers, but also in some lower versions of browsers)

terms of settlement:

Modify the back-end code, and the code / comments are as follows

/** Forcibly modify the websocket protocol in the interceptor, and modify the x-webkit deflate frame extension that some browsers do not support to permessage deflate */
if(request.getHeaders().containsKey("Sec-WebSocket-Extensions")){
    request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
}

Question 2

Problem phenomenon:

After entering the page for a few seconds, the connection is disconnected. ws can establish a connection normally, but the client and server fail to send or push messages again

Cause of problem:

After the client sends the ws connection request, the server and the client shake hands successfully (establishment is successful). After the handshake is successful, the server will have an interceptor. The function of the server interceptor is to give an identification * (the identification can use token, sessionId or the back end to generate a random number, etc.) to identify the user;
Because the protocols of each browser are different, on the window of the world browser, the server interceptor obtains the sessionId in the request header is empty (the sessionId obtained by the back-end method: request.getHeaders() is empty) *. At this time, the server cannot identify which user, so the push message fails

terms of settlement:

Even if the back end passes request Getheaders() gets a sessionId that is empty, but it can get a token * from the cookie in the request header (back-end method: request.getHeaders() Get ("cookie") *) to identify the user who sent the request, so as to solve the problem

public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                                   Map<String, Object> attributes) throws Exception {
        System.out.println("Before Handshake");
        logger.debug("Before Handshake");

        /** Forcibly modify the websocket protocol in the interceptor, and modify the x-webkit deflate frame extension that some browsers do not support to permessage deflate */
        if(request.getHeaders().containsKey("Sec-WebSocket-Extensions")){
            request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
        }

        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession(false);
            if (session != null) {
//                String userName = (String) session.getAttribute("SESSION_USERNAME");  // Generally, user entities are saved directly
                TSUser user = (TSUser) session.getAttribute(ResourceUtil.LOCAL_CLINET_USER);  //Generally, user entities are saved directly
                if (user !=null) {
                    attributes.put(ResourceUtil.WEBSOCKET_USERID,user.getId());
                } else {
                    String cookies = (String)request.getHeaders().get("cookie").get(0);
                    String token = cookies.substring(cookies.indexOf("token=")+5);
                    token = token.substring(0, token.indexOf(";"));
                    attributes.put(ResourceUtil.WEBSOCKET_USERID, token);

                }
                //Get the id and the current user role from the request
                String wsType = servletRequest.getServletRequest().getParameter("ws_type");
                String sectionId = servletRequest.getServletRequest().getParameter("section_id");
                String role = servletRequest.getServletRequest().getParameter("role");
                //Determine whether this is the WS connection of the client
                System.out.println("#############Ready to establish connection#############");
                if (StringUtils.isNotBlank(wsType) && "openLobby".equals(wsType)) {
                    //Pass in ws session for successful connection establishment
                    //If the bid id or current role is empty, no connection will be established
                    System.out.println("#############Ready to establish connection#############");
                    if (StringUtils.isNotBlank(sectionId) || StringUtils.isNotBlank(role)) {
                        System.out.println("ws_type: "+wsType);
                        System.out.println("section_id: "+sectionId);
                        System.out.println("role: "+role);
                        System.out.println("#############Prepare to establish a connection and meet the connection conditions#############");
                        attributes.put("ws_type",wsType);
                        attributes.put("section_id",sectionId);
                        attributes.put("role",role);
                    } else {
                        return false;
                    }
                }
            } else {
                String cookies = (String)request.getHeaders().get("cookie").get(0);
                String token = cookies.substring(cookies.indexOf("token=")+5);
                token = token.substring(0, token.indexOf(";"));
                attributes.put(ResourceUtil.WEBSOCKET_USERID, token);
            }
        }
        return super.beforeHandshake(request, response, wsHandler, attributes);
    }

Keywords: Javascript

Added by TJaaaay on Fri, 17 Dec 2021 13:45:40 +0200