Skip to content

WebSocket 网关让你以与 HTTP 控制器相同的装饰器和依赖注入风格处理实时连接。网关是一个带有 @WebSocketGateway 装饰器的类,它将自己注册到 Elysia 的原生 app.ws() 端点。

定义网关

typescript
import { Injectable } from "nestelia";
import {
  WebSocketGateway,
  OnOpen,
  OnMessage,
  OnClose,
  type ElysiaWsContext,
} from "nestelia";

@Injectable()
@WebSocketGateway("/ws/chat")
export class ChatGateway {
  @OnOpen()
  handleOpen(ws: ElysiaWsContext) {
    ws.send("已连接");
  }

  @OnMessage()
  handleMessage(ws: ElysiaWsContext, message: unknown) {
    ws.send(JSON.stringify({ echo: message }));
  }

  @OnClose()
  handleClose(ws: ElysiaWsContext) {
    console.log("客户端断开连接");
  }
}

在模块中注册

将网关添加到 gateways[] providers[],以便 DI 容器能够解析它:

typescript
import { Module } from "nestelia";
import { ChatGateway } from "./chat.gateway";
import { ChatService } from "./chat.service";

@Module({
  providers: [ChatGateway, ChatService],
  gateways: [ChatGateway],
})
export class ChatModule {}

处理器装饰器

装饰器Elysia 钩子参数
@OnOpen()open(ws)ws: ElysiaWsContext
@OnMessage()message(ws, msg)ws: ElysiaWsContext, message: unknown
@OnClose()close(ws, code, reason)ws: ElysiaWsContext, code: number, reason: string

三个装饰器都是可选的——只有声明的处理器才会被注册。

网关选项

将任何 Elysia ws() 选项作为第二个参数传给 @WebSocketGateway

typescript
import { t } from "elysia";

@WebSocketGateway("/ws/secure", {
  query: t.Object({ token: t.String() }),
})
export class SecureGateway {
  @OnOpen()
  handleOpen(ws: ElysiaWsContext) {
    const { token } = ws.data.query;
    // 验证 token...
  }
}

依赖注入

网关完全支持构造函数注入——在同一模块(或已导入的全局模块)中注册的任何提供者都可以被注入:

typescript
@Injectable()
@WebSocketGateway("/ws/chat")
export class ChatGateway {
  constructor(private readonly chatService: ChatService) {}

  @OnMessage()
  async handleMessage(ws: ElysiaWsContext, message: unknown) {
    const saved = await this.chatService.save(String(message));
    ws.send(JSON.stringify(saved));
  }
}

守卫(Guards)

网关类上的 @UseGuards()WebSocket 升级之前运行(在 Elysia 的 beforeHandle 中)。如果守卫返回 false,连接在建立之前就会以 403 Forbidden 被拒绝。

typescript
import { UseGuards } from "nestelia";

@Injectable()
@UseGuards(AuthGuard)
@WebSocketGateway("/ws/private")
export class PrivateGateway {
  @OnOpen()
  handleOpen(ws: ElysiaWsContext) {
    ws.send("您已通过身份验证");
  }
}

在守卫内部,context.getType() 返回 "ws"context.switchToHttp().getRequest() 返回 HTTP 升级请求,可以检查请求头和 Cookie:

typescript
@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    // context.getType() === "ws" 用于 WebSocket 网关
    const req = context.switchToHttp().getRequest<Request>();
    return req.headers.get("authorization") !== null;
  }
}

ElysiaWsContext

ElysiaWsContext 是 Elysia ElysiaWS 的宽泛泛型重导出,提供:

typescript
ws.send(data)       // 向客户端发送消息
ws.close()          // 关闭连接
ws.data             // query、headers 和其他上下文数据
ws.data.query       // 已验证的 query 参数(如果提供了 schema)

请求处理流程

HTTP 升级请求
  → beforeHandle(守卫在此运行)
  → WebSocket 连接建立
  → open 处理器
  → message 处理器(每条消息触发一次)
  → close 处理器

基于 MIT 许可证发布。