Foreword
The WebSocket
protocol allows persistent connections between the client and the server. This persistent connection feature makes WebScoket
particularly suitable for games or chat rooms, as well as for orders. Scenario of monitoring status changes and refreshing the page after submission.
Midway
provides support and encapsulation for the ws
module, which can quickly create WebSocket
services.
Server-side implementation
We use Midway.js
to implement server-side capabilities. First, create a project:
npm init midway@latest -y
Then install the dependency package of WebSocket
in the project:
npm i @midwayjs/ws@3 --save npm i @types/ws --save-dev
Enable the WebSocket
component in /src/configuration.ts
:
// src/configuration.ts import { Configuration } from '@midwayjs/core'; import * as ws from '@midwayjs/ws'; @Configuration({ imports: [ws], // ... }) export class MainConfiguration { async onReady() { // ... } }
Then we started to write the interface, first creating the socket
directory in the project directory:
├── package.json ├── src │ ├── configuration.ts ## Entry configuration file │ ├── interface.ts │ └── socket ## ws service file │ └── hello.controller.ts ├── test ├── bootstrap.js ## Service startup entrance └── tsconfig.json
Define the WebSocket service through the @WSController
decorator:
import { WSController } from '@midwayjs/core'; @WSController() export class HelloSocketController { // ... }
When a client connects, the connection
event will be triggered. We can use the @OnWSConnection()
decorator in the code to decorate a method. When each client first This method will be called automatically when connecting to the service for the first time.
import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; import * as http from 'http'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSConnection() async onConnectionMethod(socket: Context, request: http.IncomingMessage) { console.log(`namespace / got a connection ${this.ctx.readyState}`); } }
WebSocket obtains data through event listening. Midway provides the @OnWSMessage()
decorator to format received events. Every time the client sends an event, the decorated method will be executed.
import { WSController, OnWSMessage, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('message') async gotMessage(data) { return { name: 'harry', result: parseInt(data) + 5 }; } }
We can send messages to all connected clients through the @WSBroadCast
decorator.
import { WSController, OnWSConnection, Inject } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; @WSController() export class HelloSocketController { @Inject() ctx: Context; @OnWSMessage('message') @WSBroadCast() async gotMyMessage(data) { return { name: 'harry', result: parseInt(data) + 5 }; } @OnWSDisConnection() async disconnect(id: number) { console.log('disconnect ' + id); } }
At this point, the basic WebSocket
interface has been developed.
- When the client connects, we print
namespace / got a connection
; - When the client sends a message, we will return to the client a result based on the number of the input parameters plus 5;
- When the client disconnects, we print
disconnect
;
Finally, we open a WebSocket
service on the server side:
/src/config/config.default.ts
// src/config/config.default export default { // ... webSocket: { port: 3000, }, }
Next, let’s call the front end to test.
Front-end implementation
The front-end uses react
. We create a new page and enable the ws
service in useEffect
:
useEffect(async () => { const ws = new WebSocket(`ws://localhost:9999`); ws.onopen = () => { console.log('Connection successful'); ws.send(1); }; ws.onmessage = (e) => { console.log('Server response:', e); }; ws.onclose = (e) => { console.log('Close the connection, server response:', e) } }, []);
In this way, we can print out the results returned by the server on the front end. At the same time, the server obtains the log information, and the WebSocket
links of the front and back ends are opened.
Front-end:
The webSocket
service is enabled:
rear end:
Order refresh
Next, we simulate a scenario: after the front-end submits the order, it reaches the order details page. It needs to obtain the order status in real time. If the order application is passed, the success message will be displayed. The database will not be connected here, and an object will be maintained directly on the server side to simulate :
import { WSController, Inject, OnWSConnection, OnWSMessage, OnWSDisConnection, } from '@midwayjs/core'; import { Context } from '@midwayjs/ws'; import * as http from 'http'; const orderInfo = { status: 'pending', id: 1, // ...orderInfo }; @WSController() export class HelloSocketController { @Inject() ctx: Context; //The client connects for the first time @OnWSConnection() async onConnectionMethod(socket: Context, request: http.IncomingMessage) { this.ctx.logger.info(`namespace / got a connection ${this.ctx.readyState}`); setTimeout(() => { orderInfo['status'] = 'success'; }, 3000); } //Receive client message @OnWSMessage('message') async gotMessage() { if (orderInfo.status === 'success') { return { result: true }; } return { result: false }; } //Client disconnects @OnWSDisConnection() async disconnect(id: number) { console.log('disconnect ' + id); } }
- Mock an
orderInfo
on the backend; - When
WebSocket
is connected, delay three seconds to change the status oforderInfo
to simulate an algorithm review time; - Respond to the new status to the front end after three seconds;
Front-end modification:
useEffect(async () => { const ws = new WebSocket(`ws://localhost:9999`); ws.onopen = () => { console.log('Connection successful'); timer.current = setInterval(() => { ws.send(1); }, 1000); }; ws.onmessage = (e) => { console.log('Server response:', e); if (JSON.parse(e.data).result) { setOrderPass(true); } }; ws.onclose = (e) => { console.log('Close the connection, server response:', e); }; }, []); return <>Order status: {orderPass ? 'Passed' : 'Applying'}</>;
After the transformation, the front-end page is refreshed, and the order status is asynchronously changed to passed three seconds later, achieving the effect of page monitoring and real-time refresh. Is this effect better than the traditional Http scheduled polling
?
End
This article uses Midway
0~1 to open up the front-end and back-end ws
links, and finally demonstrates the advantages of ws
and its comparison with traditional round-robin through actual business scenarios. differences in inquiry plans.