Midway.js打通WebSocket前后端监听通道

您好, 如果喜欢我的文章或者想上岸大厂,可以关注公众号「量子前端」,将不定期关注推送前端好文、分享就业资料秘籍,也希望有机会一对一帮助你实现梦想

前言

WebSocket协议允许客户端和服务端持久化连接,这种可以持续连接的特性使得WebScoket特别适用于游戏或者聊天室的场景,同样也适用于订单提交完以后监听状态变化进行页面刷新的场景。

Midway中提供了对于ws模块的支持和封装,能够快速创建WebSocket服务。

服务端实现

我们采用Midway.js来实现服务端能力,首先创建一个项目:

npm init midway@latest -y

然后在项目中安装WebSocket的依赖包:

npm i @midwayjs/ws@3 --save
npm i @types/ws --save-dev

/src/configuration.ts中开启WebSocket组件:

// src/configuration.ts
import { Configuration } from '@midwayjs/core';
import * as ws from '@midwayjs/ws';@Configuration({imports: [ws],// ...
})
export class MainConfiguration {async onReady() {// ...}
}

然后我们开始写接口,首先在项目目录创建socket目录:

├── package.json
├── src
│   ├── configuration.ts          ## 入口配置文件
│   ├── interface.ts
│   └── socket                    ## ws 服务的文件
│       └── hello.controller.ts
├── test
├── bootstrap.js                  ## 服务启动入口
└── tsconfig.json

通过 @WSController 装饰器定义 WebSocket 服务:

import { WSController } from '@midwayjs/core';@WSController()
export class HelloSocketController {// ...
}

当有客户端连接时,会触发 connection 事件,我们在代码中可以使用 @OnWSConnection() 装饰器来修饰一个方法,当每个客户端第一次连接服务时,将自动调用该方法。

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 是通过事件的监听方式来获取数据。Midway 提供了 @OnWSMessage() 装饰器来格式化接收到的事件,每次客户端发送事件,被修饰的方法都将被执行。

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 };}
}

我们可以通过 @WSBroadCast 装饰器将消息发送到所有连接的客户端上。

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);}
}

至此,基础的WebSocket接口就开发好了。

  • 当客户端连接时,我们会打印namespace / got a connection
  • 当客户端发送消息时,我们会返回给客户端基于入参的编号附加5的结果;
  • 当客户端断开连接时,我们会打印disconnect

最后我们在服务端开启一个WebSocket服务:

/src/config/config.default.ts

// src/config/config.default
export default {// ...webSocket: {port: 3000,},
}

接下来我们前端来调用测试下。

前端实现

前端使用react,我们建一个新页面,在useEffect中开启ws服务:

  useEffect(async () => {const ws = new WebSocket(`ws://localhost:9999`);ws.onopen = () => {console.log('连接成功');ws.send(1);};ws.onmessage = (e) => {console.log('服务端响应:', e);};ws.onclose = (e) => {console.log('关闭连接,服务端响应:', e)}}, []);

这样我们在前端就可以打印出服务端返回的结果,同时服务端获取到了日志信息,前后端的WebSocket链路打通了。

前端:

image.png

开启了webSocket服务:

image.png

后端:

image.png

订单刷新

接下来我们模拟一个场景:当前端提交完订单后到了订单详情页,需要实时获取订单状态,如果订单申请通过,则展示成功信息,这里就不连接数据库了,直接在服务端维护一个对象来模拟:

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;// 客户端第一次连接@OnWSConnection()async onConnectionMethod(socket: Context, request: http.IncomingMessage) {this.ctx.logger.info(`namespace / got a connection ${this.ctx.readyState}`);setTimeout(() => {orderInfo['status'] = 'success';}, 3000);}// 收到客户端消息@OnWSMessage('message')async gotMessage() {if (orderInfo.status === 'success') {return { result: true };}return { result: false };}// 客户端断开连接@OnWSDisConnection()async disconnect(id: number) {console.log('disconnect ' + id);}
}
  • 在后端mock一个orderInfo
  • WebSocket连接后,延迟三秒改变orderInfo的状态,模拟一个算法审核的时间;
  • 三秒后响应给前端新状态;

前端配合改造:

useEffect(async () => {const ws = new WebSocket(`ws://localhost:9999`);ws.onopen = () => {console.log('连接成功');timer.current = setInterval(() => {ws.send(1);}, 1000);};ws.onmessage = (e) => {console.log('服务端响应:', e);if (JSON.parse(e.data).result) {setOrderPass(true);}};ws.onclose = (e) => {console.log('关闭连接,服务端响应:', e);};}, []);return <>订单状态:{orderPass ? '通过' : '申请中'}</>;

改造后,前端页面刷新,三秒后订单状态异步更改为通过,达到了页面监听实时刷新的效果,这样的效果是不是比传统Http定时轮询性能更优呢?

image.png

结尾

本文通过Midway0~1打通前后端ws链路,并在最后通过实际业务场景展示了ws的优势以及与传统轮询方案的差异。

如果喜欢我的文章或者想上岸大厂,可以关注公众号「量子前端」,将不定期关注推送前端好文、分享就业资料秘籍,也希望有机会一对一帮助你实现梦想。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/164847.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32_project:led_beep

代码&#xff1a; 主要部分&#xff1a; #include "stm32f10x.h" // Device header #include "delay.h"// 给蜂鸣器IO口输出低电平&#xff0c;响&#xff0c;高&#xff0c;不向。 //int main (void) //{ // // 开启时钟 // RC…

接口自动化面试题

1.http请求都包含哪些内容&#xff0c;请求头和请求体有哪些内容 请求行/请求头/请求体/空行 请求行&#xff1a;请求方法字段、URL字段、http协议版本 例如&#xff1a;GET /index.html HTTP/1.1 请求方法&#xff1a;GET、POST、PUT、DELETE、OPTIONS、TRACE、CO…

MySQL InnoDB数据存储结构

1. 数据库的存储结构&#xff1a;页 索引结构给我们提供了高效的索引方式&#xff0c;不过索引信息以及数据记录都是保存在文件上的&#xff0c;确切说是存储在页结构中。另一方面&#xff0c;索引是在存储引擎中实现的&#xff0c;MySQL服务器上的存储引擎负责对表中数据的读…

Java基础-015-System.java常用类

Java基础-015-System.java常用类 1、标准输入输出2、获取属性3、System.java初始化4、设置标准输出System.out java/lang/System.java 1、标准输入输出 System.in、System.out public class Test {public static void main(String[] args) {String charsetName String.valueOf…

wpf添加Halcon的窗口控件报错:下列控件已成功添加到工具箱中,但未在活动设计器中启用

报错截图如下&#xff1a; 注意一下新建工程的时候选择wpf应用而不是wpf应用程序。 添加成功的控件&#xff1a;

C++常用格式化输出转换

在C语言中可以用printf以一定的格式打印字符&#xff0c;C当然也可以。 输入输出及命名空间还不太了解的小伙伴可以看一看C入门讲解第一篇。  在C中&#xff0c;可以用流操作符&#xff08;stream manipulators&#xff09;控制数据的输出格式&#xff0c;这些流操作符定义在2…

大语言模型(LLM)综述(七):大语言模型设计应用与未来方向

A Survey of Large Language Models 前言8 A PRACTICAL GUIDEBOOK OF PROMPT DESIGN8.1 提示创建8.2 结果与分析 9 APPLICATIONS10 CONCLUSION AND FUTURE DIRECTIONS 前言 随着人工智能和机器学习领域的迅速发展&#xff0c;语言模型已经从简单的词袋模型&#xff08;Bag-of-…

Workbench环境中常见问题

问题描述&#xff1a;1 解决方案&#xff1a;2 问题描述&#xff1a;在WB中启动Fluent&#xff0c;报错&#xff0c;提示 “The requested operatjon requires elevation” 解决方案&#xff1a;这个问题是因为WB主程序没有管理员权限导致。使用管理员权限启动WB后&#xff0c…

【达梦数据库】mysql与达梦整数类型对比关系

最近遇了mysql 和达梦整数类型的数据范围对比&#xff0c;做了个表格供大家分享 对比表格 要说明的是我整理的时候&#xff0c;达梦貌似没有无符号整数类型&#xff08;防杠保护&#xff09;&#xff0c;也就是只能将mysql/dm 的有符号整数类型的的范围值进行对比 MYSQL - t…

HK WEB3 MONTH Polkadot Hong Kong 火热报名中!

HK Web3 Month 11月除了香港金融科技周外&#xff0c;HK Web3 Month又是一大盛事&#xff0c;从10月29日开始开幕直到11月18日结束。此次将齐聚世界各地的Web3产业从业者、开发者、社群成员和学生来参与本次盛会。除外&#xff0c;超过75位产业知名的讲者与超过50场工作坊将为…

Docker Stack部署应用详解+Tomcat项目部署详细实战

Docker Stack 部署应用 概述 单机模式下&#xff0c;可以使用 Docker Compose 来编排多个服务。Docker Swarm 只能实现对单个服务的简单部署。而Docker Stack 只需对已有的 docker-compose.yml 配置文件稍加改造就可以完成 Docker 集群环境下的多服务编排。 stack是一组共享…

sql学习笔记(三)

目录 1.四舍五入 2.向上取整 3.向下取整 4.Hive 分区 5.case when条件语句 6.日期函数 7.字符串函数 8.窗口函数 1️⃣排序函数 1.四舍五入 round select round(3.14) —>3 2.向上取整 ceiling select ceiling(12.15) —>13 3.向下取整 floor select floor(12…