NestJS WebSocket网关异常过滤器无法触发问题求助
WebSocket异常过滤器未触发的问题解决
问题原因
NestJS的WebSocket异常过滤器默认仅作用于被@SubscribeMessage()装饰的消息处理方法,而handleConnection、handleDisconnect这类生命周期钩子中抛出的异常,不会自动被过滤器捕获。你的代码中异常是在handleConnection调用的auth方法中抛出的,因此过滤器的catch方法不会被触发。
解决方案
方案1:手动捕获并处理异常
直接在handleConnection中用try/catch包裹认证逻辑,手动处理错误:
handleConnection(client: WebSocket, req: any) { console.log('connecting'); try { this.auth(req); } catch (error) { // 发送错误消息给客户端 client.send(JSON.stringify({ error: error instanceof WsException ? error.getError() : 'Authentication failed' })); // 关闭连接 client.close(401, 'Unauthorized'); } }
方案2:手动调用过滤器
如果你希望复用已有的WebSocketExceptions过滤器,可以在catch块中手动调用过滤器的catch方法,需要手动构造ArgumentsHost:
import { ArgumentsHost } from '@nestjs/common'; // ... handleConnection(client: WebSocket, req: any) { console.log('connecting'); const filter = new WebSocketExceptions(); try { this.auth(req); } catch (error) { // 构造WebSocket类型的ArgumentsHost const host = ArgumentsHost.create([ 'ws', // 上下文类型 client, // WebSocket客户端实例 req, // 请求对象 ]); filter.catch(error, host); } }
方案3:改用WebSocket守卫处理认证(推荐)
将认证逻辑移到WebSocket守卫中,守卫会在handleConnection执行前拦截请求,认证失败时直接关闭连接:
- 创建守卫:
// ws-auth.guard.ts import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import { WsException } from '@nestjs/websockets'; import { verify } from 'jsonwebtoken'; import { config } from 'src/config'; import { IncomingMessage } from 'http'; @Injectable() export class WsAuthGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const client = context.switchToWs().getClient(); const req: IncomingMessage = context.switchToWs().getData(); // 连接阶段的请求对象通过getData获取 const token = this.extractTokenFromHeader(req); if (!token) { client.close(401, 'No Token'); throw new WsException('No Token'); } try { verify(token, config.serviceSecret); return true; } catch (error) { client.close(401, 'Invalid Token'); throw new WsException('Invalid Token'); } } private extractTokenFromHeader(req: IncomingMessage): string | undefined { const [type, token] = req.headers.authorization?.split(' ') ?? []; return type === 'Bearer' ? token : undefined; } }
- 在网关中使用守卫:
@WebSocketGateway({ path: '/ws/operator' }) @UseGuards(WsAuthGuard) // 添加守卫 export class WsOperatorServiceGateway implements OnGatewayConnection, OnGatewayDisconnect { handleConnection(client: WebSocket, req: any) { console.log('connecting'); // 认证已通过,无需再调用auth方法 } // ...其他方法 }
内容的提问来源于stack exchange,提问作者user24484638
相关产品推荐
相关产品推荐

