Recently, a function needs to be implemented. The backend connects to the controller of radar hardware through TCP protocol, and the frontend connects to the backend through websocket. When the controller triggers a message, it notifies the frontend of the information;
The first idea is to write a backend service separately to implement websocket. The debugging was successful. Later, I discovered a plug-in express-ws, so I decided to change my thinking and studied it. The final code is as follows, hoping to help more friends and no longer be afraid of websocket.
First write a front-end websocket service. Here I chose to abandon the singleton mode and adopt the idea that whoever calls is responsible for the destruction
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { LoginService } from '../login/'; import { environment } from 'src/environments/environment'; export class WsConnect { ws!:WebSocket; sendWs!:(msg:string)=>void; closeWs!:()=>void; result!:Observable<any> } @Injectable({providedIn:"root"}) export class WebsocketService { origin = ('http', 'ws'); constructor( private loginService: LoginService ) { } getUrl(path:string){ return `${}${path}`; } connect(path:string):WsConnect{ let url = (path); let ws = new WebSocket(url, ); // Put jwt information here, but there is no other place to be placed. Some netizens suggest putting the address first and then replacing the header in nginx. I don’t think it’s down-to-earth enough return { ws, sendWs:function(message:string){ (message); }, closeWs:function(){ (); }, result:new Observable( observer => { = (event) => { ()};//Receive data = (event) => {("ws connection error:",event);(event)};// An error occurred = (event) => {("WS connection disconnected:",event); () };//End Event = (event) => { ("WS connection is successful:",event);};//End Event } ) } } }
Then call it in the component
import { Component, OnDestroy, OnInit } from '@angular/core';import { WebsocketService, WsConnect } from '../utils/'; @Component({ selector: 'app-car-measure', templateUrl: './', styleUrls: ['./'] }) export class CarMeasureComponent implements OnInit , OnDestroy{ connect!:WsConnect; constructor(public wsService:WebsocketService) { } ngOnInit() { (); } connectServer(){ = ('/websocket/carMeasure') ( (data:any) => { //Receive a message from the server ("Server Message:",data); setTimeout(() => { ("This is a message sent from the client"); }, 5000); } ) } ngOnDestroy() { (); // This method destroys the entire ws instead of unsubscribe, so students in need can consider unsubscribe. } }
The backend introduces express-ws to encapsulate a callable file. Some code borrows from online code and makes some improvements.
// const express = require('express'); const router = (); const expressWs = require('express-ws') // Initializationlet WS = null; // Declare a channel classlet channels = null; let pathList = [ '/websocket/carMeasure', '/path2' ] function initWebSocket(app) { WS = expressWs(app) //Mixed in app, wsServer stores all connected instances // Create a channel channels = new channel(router) (path=>{ (path) // ('/carMeasure/websocket/carSize') }) (router) } // Channel classclass channel { router; constructor(props) { = props; } createChannel(path) { // Create a channel ( path, (ws, req) => { // Add custom information to the socket to get it, and expressws will be automatically placed into ().clients. // It will automatically delete or add clients according to active users ws['wsPath'] = path; ws['userId'] = ._id; ws['roleId'] = ; ('message', (msg) => getMsg(msg, path)) ('close', (code) => close(code, path)) ('error', (e) => error(e, path)) }) } } /** * * @param {*} msg message content * @param {String} from Source */ // Listen to messageslet getMsg = (msg, from) => { (msg, from); // SendMsgAll({path:'/path2', data: msg }) } // Send a messagelet sendMsg = (client, data) => { if (!client) return ((data)) } let close = (code) => { ('Close the connection', code); } let error = (e) => { ('error: ', e); } // Mass/** * * @param {String} path The source of the user that needs to be sent. Routing, default all * @param {*} data sent */ function sendMsgToClients(clients,data){ ((client)=> { if (client._readyState == 1) { sendMsg(client, data) } }) } function sendMsgToAll(data = "") { let allClientsList = (().clients) sendMsgToClients(allClientsList,data) } function sendMsgToPath(data = "", path = '') { let allClientsList = (().clients).filter((ws)=>ws['wsPath'] == path) sendMsgToClients(allClientsList,data) } function sendMsgToId(data = "", userId = '') { let allClientsList = (().clients).filter((ws)=>ws['userId'] == userId) sendMsgToClients(allClientsList,data) } function sendMsgToRole(data = "", roleId = '') { let allClientsList = (().clients).filter((ws)=>ws['roleId'] == roleId) sendMsgToClients(allClientsList,data) } = { initWebSocket, sendMsgToAll, sendMsgToPath, sendMsgToId, sendMsgToRole, }
Then call it inside
const {initWebSocket} = require('./public/utils/websocket') initWebSocket(app)
This involves the issue of permission verification, and you can also directly verify jwt
((req,res,next) => { if(!(item => (item))) { let httpJwt= ['jwt']; let wsJwt= ['sec-websocket-protocol']; // Verify the websocket's identity information here, other codes (httpJwt || wsJwt).then(res => { //Encapsulated jwt verification req["userInfo"] = res; //Put some information to facilitate subsequent operations next() }).catch(e => { (e); (401).send('invalid token') }) } else { next() } })
Everything is done, the last step is to wait for the hardware device to trigger it. The code of other tcp clients will not be released to interfere with everyone, just call it roughly
var {sendMsgToPath} = require('../public/utils/websocket'); sendMsgToPath((result), ); // Noticewebsocketortcp的传输都只能用字符串orblob
Also, please note that you need to configure nginx proxy. You should be clear about the configuration of nginx. I won’t say much about it here. Note that there are several options here. One is the front-end, which can make WS services into a singleton, and the other is that the back-end routing can actually be written in the http routing file. There is also the use of the back-end WS client, which uses the express-ws own method. Of course, you can also write objects to collect clients by yourself (not very recommended)
After thinking about it, I will release it for Xiaobai. Here is
{ "/api": { "target": "http://localhost:3000", "secure": false, "logLevel": "debug", "changeOrigin": true, "pathRewrite": { "^/api": "/" } }, "/websocket":{ "target": "http://localhost:3000", "secure": false, "ws": true } }
After all, it is important to teach you step by step. If you don’t know, you have to know. This is put into the server.
worker_processes 1; events { worker_connections 1024; } http { server { listen 80; server_name localhost; client_max_body_size 20M; underscores_in_headers on; include /etc/nginx/; gzip on; gzip_static on; gzip_min_length 1000; gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; location /{ root /usr/share/nginx/html; index ; try_files $uri $uri/ /; } location /api { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://localhost:3000; } location /websocket { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } }
This is the end of this article about angular + express implementing websocket communication. For more related angular websocket communication content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!