The front-end code

class Socket { constructor({ url = '', token = '', roomId = '', callback = () => {} }) { this.url = url; this.callback = callback; this.token = token; this.roomId = roomId; this.ws = {}; this.init(); } init() { this.ws = new WebSocket(`wss://${this.url}`); This.ws. Onopen = () => this.onOpen(this.token, this.roomId); This.ws. Onmessage = e => this.onMessage(e, this.callback); This.ws. Onerror = this.onError; // This.ws. Onclose = this.onclose; } onOpen(token, roomId) {this.send({event: 'auth', message: {token, roomId}}); } send(data) { this.ws.send(JSON.stringify(data)); } onMessage(e, callback) { const data = JSON.parse(e.data); Switch (data.event) {case 'noAuth': // Failed to verify, return the login page location.href = '/login'; break; This. send({event: 'heartbeat', message: 'pong'}); clearTimeout(this.pingTimeout); this.pingTimeout = setTimeout(() => { this.close(); this.onError(); }, 30000 + 1000); break; default: callback(data); }} onError() {console.log('websocket connection error '); SetTimeout (() => {this.init(); }, 1000); } onClose() {console.log('websocket connection is down '); } close() {// Close the webSocket connection. Disable the heartbeat detection timer to prevent the original timer from running after the connection is disconnected clearTimeout(this.pingtimeout); this.ws.close(); }}Copy the code

The back-end code

import WebSocket from "ws"; import fs from "fs"; import https from "https"; import jwt from "jsonwebtoken"; class Socket { constructor(config) { this.config = { port: 8080, ... config, }; this.wss = {}; this.init(); } init() { const server = https.createServer({ cert: fs.readFileSync( __dirname + "/httpsConfig/5163307_www.pengjianming.top.pem" ), key: fs.readFileSync( __dirname + "/httpsConfig/5163307_www.pengjianming.top.key" ), }); This. WSS = new websocket. Server({Server}); This.wss. on("connection", (ws) => {// The connection is successful and the heartbeat detection is enabled. this.heartbeat(ws); ws.on("message", (msg) => this.message(ws, msg)); ws.on("close", () => this.close(ws, this.wss)); }); server.listen(8080); } message(ws, msg) { const data = JSON.parse(msg); Const event = {// After the authentication, add the authentication information and add the corresponding user information to the ws auth: (params) => { const auth = jwt.verify(params.token, "shared-secret"); if (auth) { ws.user = auth; ws.roomId = params.roomId; } else { ws.send( JSON.stringify({ event: "noAuth", }) ); {ws.isalive: () => {ws.isalive = true; }}; event[data.event](data.message); } send(user_name, message) {// Send a message to a client based on the user name [...this.wss.clients]. Filter ((client) =>! client.roomId) .forEach((client) => { if ( client.readyState === WebSocket.OPEN && client.user.user_name === user_name )  { client.send(JSON.stringify({ event: "tip", message })); }}); } broadcast(roomId, [...this.wss.clients].filter((client) => client.roomId).foreach ((client) => {if (user_id); client.readyState === WebSocket.OPEN && client.roomId === roomId && user_id ! == client.user.id ) { client.send(JSON.stringify({ event: "chat" })); }}); } close(ws) {// Close the connection to close the corresponding timer clearInterval(ws-interval); Websocket ws.interval = setInterval(() => {if (ws.isalive === =) false) return ws.terminate(); ws.isAlive = false; ws.send( JSON.stringify({ event: "heartbeat", message: "ping", }) ); }, 30000); } } export default new Socket();Copy the code

The process that

Initialize the

When the object is created, init method is called to create the webSocket instance and the connection is successful. At this time, onOpen will also be called to verify the identity with the back end and create the connection information. According to the token passed, the identity can be determined and the single point of information can be sent If the identity verification passes, the corresponding connection information is set. If the identity verification fails, the noAuth event of event will be sent to inform the client that the identity verification fails. After receiving the noAuth event, the client will switch back to the login page for re-login

The heartbeat detection

Create a WebSocket instance. If the connection succeeds, the backend will start heartbeat detection. If the connection succeeds, isAlive = will be set first If the client does not send the heartbeat back within the specified time, set isAlive =. If the client does not send the heartbeat back within the specified time, set isAlive = True, so, at the beginning of the second heartbeat detection, will think that the client disconnected died directly, if the client returns corresponding to the heartbeat, the heartbeat is normal, every time the client receives a heartbeat, all would the clearance before the timer, open up a new timer, if within the prescribed time, the server didn’t detect heartbeat again, will be closed This client, reconnect

Agreement that

If HTTP is used, the protocol is WS, if HTTPS is used, the protocol is WSS, and the certificate file needs to be set

Broadcast information

Iterate over all connected clients, filter by the roomId passed when they connect, and then send the information

Single point sending information

Passes through all connected clients, based on previously authenticated information

Pass the message

The message needs to be converted to a character, not converted to get the message type

How to use

this.socket = new Socket({ url: 'www.pengjianming.top:8080', token: getToken(), roomId: this.$route.query.id, callback: data => { if (data.event === 'chat') { this.getTicket(); }}});Copy the code

After creation, every time the server returns a message, callback will be called if the event is not the specified heartbeat and noauth, where the desired event notification can be made