参考文档:NestJs中文文档-WebSocket

WebSocket网关

要使用WS,必须先加载适配器,Nestjs默认支持两种适配器,socket.io与ws库.因为ws库支持原生的websockets,所以性能上更具优势,所以我们使用ws的适配器

// src/main.ts
import { WsAdapter } from '@nestjs/platform-ws';
async function bootstrap() {
    ...
    app.useWebSocketAdapter(new WsAdapter(app));
    await app.listen(3000);
}
bootstrap();

创建Websockets网关

// src/socket-test/socket-test.gateway.ts
import {
  WebSocketGateway,
  SubscribeMessage,
  MessageBody,
  ConnectedSocket,
  OnGatewayDisconnect
} from "@nestjs/websockets";
import { Socket } from "socket.io";
import { Logger } from "@nestjs/common";

@WebSocketGateway(3002)
export class SocketTestGateway implements OnGatewayDisconnect {
  // 在线用户集合
  _oneliners: Record<string, any> = {};

  handleDisconnect(client: Socket) {
    let removeKey = null;
    Object.keys(this._oneliners).map(key => {
      if (this._oneliners[key] === client) {
        removeKey = key;
      }
    });
    delete this._oneliners[removeKey];
    Logger.log(`断开连接,userId: ${removeKey}`)
  }

  // 用户上线
  @SubscribeMessage("online")
  online(@MessageBody() data: any, @ConnectedSocket() client: Socket) {
    this._oneliners[data.sendId] = client;
    Logger.log(`用户登录,userId: ${data.sendId}`)
    Logger.log(`在线用户: ${Object.keys(this._oneliners)}`)
    return { event: "online", data };
  }

  // 心跳
  @SubscribeMessage("heartbeat")
  heartbeat() {
    return { event: "heartbeat" };
  }

  // 发送消息
  @SubscribeMessage("send")
  async send(@MessageBody() data: any) {
    this._oneliners[data.receiveId].send(JSON.stringify(
      { event: "receive", data }
    ));
    return { event: "send", data };
  }
}

网关写好后别忘了放到提供者中注册,否则无法生效

// src/socket-test/socket-test.module.ts
import { Module } from '@nestjs/common';
import { SocketTestGateway } from './socket-test.gateway';

@Module({
  providers: [SocketTestGateway]
})
export class SocketTestModule {}

最后不要忘记在AppModule中注入SocketTestModule

// src/app.module.ts
import { Module } from "@nestjs/common";
import { SocketTestModule } from "./socket-test/socket-test.module";

@Module({
  imports: [
    ...
    SocketTestModule
  ],
  ...
})
export class AppModule {
}