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

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

相关推荐
椰椰椰耶7 小时前
[网页五子棋][对战模块]实现游戏房间页面,服务器开发(创建落子请求/响应对象)
服务器·websocket·spring
前端卧龙人8 小时前
你的nest项目不要再使用console.log
nestjs
汤姆yu10 小时前
基于微信小程序的垃圾分类系统
微信小程序·小程序
Mr.Liu615 小时前
小程序32-简易双向数据绑定
前端·微信小程序·小程序
佩奇的技术笔记18 小时前
WebSocket与Reactor模式:构建实时交互应用
websocket·网络协议
Mr.Liu620 小时前
小程序33-列表渲染
前端·微信小程序·小程序
椰椰椰耶1 天前
[网页五子棋][匹配模块]处理开始匹配/停止匹配请求(匹配算法,匹配器的实现)
java·python·websocket·spring·java-ee
我叫汪枫1 天前
解决微信小程序中 Flex 布局下 margin-right 不生效的问题
微信小程序·小程序
plusone2 天前
【Nest指北系列-源码】(四)NestContainer
nestjs
00后程序员张2 天前
面对 UI 差异化的调试难题:本地多设备测试中的 WebDebugX 应用实录
websocket·网络协议·tcp/ip·http·网络安全·https·udp