放弃云数据库!基于NestJS的WebSocket实时通信方案实践

背景

在开发3D骰子联机小程序时,多人游戏功能需要实时同步房间的操作状态(如房主开盅动作)。初期采用小程序云开发数据库的watch监听机制实现状态同步,虽能完成基础功能,但存在致命体验短板------云函数响应延迟高达1-2秒,与骰子游戏强实时的特性产生明显冲突。

于是为追求更丝滑的实时交互的用户体验,决定选择通过 WebSocket 重构通信层,下文将详解一下通过 nest 实现与小程序实时通信的方案。

实现

首先我们通过 nest 的脚手架来初始化一下项目

arduino 复制代码
nest new websocket-demo

运行一下项目,启动成功

接着我们安装对应的所需的websocket的依赖

css 复制代码
npm i --save @nestjs/websockets @nestjs/platform-ws ws

最开始用的 socket.io 依赖实现,结果后面发现小程序不支持 socket.io ,需要下载一些兼容库来结合使用,于是就换了方案。

接下来我们需要为应用注入 WebSocket 适配器,在main.ts中配置一下 主要作用

  • 将传统的 HTTP 服务扩展为 同时支持 HTTP + WebSocket 双协议
  • 通过适配器模式,让 WebSocket 的底层实现(如 wssocket.io 库)与框架的路由、中间件等系统无缝对接。
js 复制代码
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { WsAdapter } from '@nestjs/platform-ws';
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useWebSocketAdapter(new WsAdapter(app));
  await app.listen(3000);
}
bootstrap();

接下来需要配置一下 WebSocket 网关

js 复制代码
import { SubscribeMessage, WebSocketGateway, WebSocketServer, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
import { Server, WebSocket } from 'ws';

@WebSocketGateway(3001) // 指定ws端口号,不配置则默认与http服务相同端口
export class WsGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer()
  server: Server;

  // 初始化后执行
  afterInit(server: Server) {
    console.log('WebSocket server initialized');
  }

  // 处理新连接
  handleConnection(client: WebSocket, ...args: any[]) {
    console.log('Client connected:');
  }

  // 处理断开连接
  handleDisconnect(client: WebSocket) {
    console.log(`Client disconnected: ${client}`);
  }

  // 消息处理示例
  @SubscribeMessage('message') // 这里的message对应的是前端发送ws请求的里的event值
  handleMessage(client: WebSocket, payload: any): string {
    console.log('handleMessage message:', payload);
    client.send(JSON.stringify({ event: 'message', data: `我收到了你发的消息${payload}` })); // 回发消息
    return 'OK';
  }
}

还需要在 app.module.ts 中引入 socket 网关

js 复制代码
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { WsGateway } from './ws.gateway';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService, WsGateway], // 这里
})
export class AppModule {}

我们重新跑一下后端服务

然后在小程序中的app.vue中的 onLaunch 写连接本地 WebSocket 服务的代码

js 复制代码
const conSocket = wx.connectSocket({
  url: 'ws://localhost:3001',
  success: () => console.log('Connecting...'),
})

// 监听事件
conSocket.onOpen(() => {
  console.log('Connected!');
});

conSocket.onMessage((res: any) => {
  const { data } = res
  console.log('onMessage-msg', data);
});

conSocket.onError((err) => {
  console.error('Error:', err);
});

conSocket.onClose(() => {
  console.log('Connection closed');
});

小程序项目运行起来

发现连接成功了!!!

接下来我来试一下双向通信,在连接打开的时候,我们给服务端发送点内容

js 复制代码
conSocket.onOpen(() => {
    console.log('Connected!');
    conSocket.send({
      data: JSON.stringify({
        event: 'message',
        data: {
          msg: 'Hello, server!'
        }
      }),
      success: () => console.log('Message sent')
    })
  });

可以看到服务器与小程序之间的双向通信没问题,并且响应很快,非常符合我们的联机功能。

✨ 总结

  • 旧方案:云数据库watch监听

    • 延迟1-2秒,体验割裂
    • 被动轮询,资源消耗大
  • 新方案:NestJS+WebSocket

    • 延迟<100ms,毫秒级响应
    • 主动推送,节省资源

对于前端来说,用户体验极其重要,我自己在开发过程中,都会让自己从用户的角度,来体验流程,这也有助于自己去思考,去进行一些性能优化。

相关推荐
胡西风_foxww4 小时前
微信小程序转Vue2组件智能提示词
微信小程序·小程序·提示词·智能体·vue2组件
牧码岛11 小时前
服务端之nestJS常用异常类及封装自定义响应模块
node.js·nestjs
换日线°20 小时前
css 不错的按钮动画
前端·css·微信小程序
qq_427506081 天前
JavaScript和小程序写水印的方法示例
前端·算法·微信小程序
盏灯1 天前
🔥🔥🔥websocket 前后端通信,接受命令,并执行
前端·后端·websocket
gongzemin1 天前
使用Node.js开发微信第三方平台后台
微信小程序·node.js·express
猫头_1 天前
uni-app 转微信小程序 · 避坑与实战全记录
前端·微信小程序·uni-app
weixin_491853311 天前
Spring Boot 中整合WebSocket
spring boot·后端·websocket
超级小忍2 天前
深入浅出:在 Spring Boot 中构建实时应用 - 全面掌握 WebSocket
spring boot·后端·websocket
qingyingWin2 天前
原生微信小程序研发,如何对图片进行统一管理?
前端·微信小程序