NestJS中WebSocket全局守卫/拦截器不生效问题及解决方案咨询
NestJS WebSocket 全局守卫/拦截器不生效的原因及解决办法
原因
NestJS中,通过app.useGlobalGuards()和app.useGlobalInterceptors()注册的全局守卫、拦截器,默认仅绑定到HTTP请求处理管道。而WebSocket(包括默认的socket.io适配器)属于独立的通信上下文,拥有专属的执行管道,因此不会自动继承HTTP的全局配置,导致WebSocket事件触发时这些全局守卫/拦截器不生效。
解决办法
方法一:在网关类上直接应用装饰器(推荐,简单直接)
在你的WebSocket网关类上,使用@UseGuards()和@UseInterceptors()装饰器,传入对应的守卫/拦截器类,即可让该网关下的所有事件处理方法应用这些逻辑。
示例代码:
import { WebSocketGateway, SubscribeMessage, MessageBody } from '@nestjs/websockets'; import { UseGuards, UseInterceptors } from '@nestjs/common'; import { YourAuthGuard } from './your-auth.guard'; import { YourLoggingInterceptor } from './your-logging.interceptor'; @WebSocketGateway() @UseGuards(YourAuthGuard) @UseInterceptors(YourLoggingInterceptor) export class AppGateway { @SubscribeMessage('chat') handleChat(@MessageBody() message: string) { return `Received message: ${message}`; } }
方法二:全局注册WebSocket专属的守卫/拦截器
如果需要让所有网关都共享全局的守卫/拦截器,可以通过NestJS的模块容器为WebSocket上下文注册全局逻辑:
全局注册守卫
// main.ts import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { YourAuthGuard } from './your-auth.guard'; async function bootstrap() { const app = await NestFactory.create(AppModule); // HTTP全局守卫 app.useGlobalGuards(new YourAuthGuard()); // WebSocket全局守卫 const rootModule = app.select(AppModule); rootModule.registerWsGuard(new YourAuthGuard()); await app.listen(3000); } bootstrap();
全局注册拦截器
// main.ts import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { YourLoggingInterceptor } from './your-logging.interceptor'; async function bootstrap() { const app = await NestFactory.create(AppModule); // HTTP全局拦截器 app.useGlobalInterceptors(new YourLoggingInterceptor()); // WebSocket全局拦截器 const rootModule = app.select(AppModule); rootModule.registerWsInterceptor(new YourLoggingInterceptor()); await app.listen(3000); } bootstrap();
注意事项:WebSocket守卫/拦截器的适配
WebSocket的执行上下文与HTTP不同,在编写守卫和拦截器时,需要通过context.switchToWs()获取WebSocket相关的客户端和数据:
示例WebSocket守卫
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { WsException } from '@nestjs/websockets'; @Injectable() export class YourAuthGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { // 获取WebSocket客户端 const client = context.switchToWs().getClient(); // 从握手信息中获取认证凭证 const token = client.handshake.headers.authorization; if (!token) { throw new WsException('未授权连接'); } // 此处添加你的认证逻辑 return true; } }
示例WebSocket拦截器
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class YourLoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const startTime = Date.now(); const client = context.switchToWs().getClient(); const eventData = context.switchToWs().getData(); console.log(`WebSocket客户端[${client.id}]触发事件,数据:${JSON.stringify(eventData)}`); return next.handle().pipe( tap(() => console.log(`WebSocket响应完成,耗时:${Date.now() - startTime}ms`)), ); } }
内容的提问来源于stack exchange,提问作者Mansouri Rayen
相关产品推荐
相关产品推荐

