放弃云数据库!基于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,毫秒级响应
    • 主动推送,节省资源

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

相关推荐
悟空瞎说15 小时前
NestJS 12 预览版重磅来袭:全面原生 ESM 正式落地
nestjs
爱勇宝2 天前
我想认真做一件小事:让孩子和家长更好地互动
微信小程序·小程序·云开发
唯火锅不可辜负2 天前
避坑指南:iOS 下 scroll-view 嵌套 fixed 布局的“翻车”现场与修复
微信小程序
didiplus2 天前
运维人的随身神器:我把25个常用工具塞进了微信小程序
微信小程序
一份执念3 天前
uni-app 小程序分包限制处理与主包体积优化实战
前端·微信小程序
一份执念3 天前
ECharts 安装与使用完全指南:从全量引入到小程序分包优化
微信小程序·echarts
skiyee4 天前
🔥UniApp 仅需 5 行代码!实现所有页面中控制应用主题变化
前端·微信小程序
Jinkey5 天前
要用户手机号真的是为了打骚扰电话吗?浅谈微信生态会员账号体系与资产合并
后端·微信·微信小程序
用户4324281061147 天前
微信小程序从0到1接入微信支付的完整攻略
微信小程序
spmcor9 天前
微信小程序 setStorageSync 踩坑实录:别让"顺手一存"变成"隐形炸弹"
微信小程序