英文:
How to catch validation error message - Nestjs Gateway Socket.io
问题
我有一个验证管道,用于检查用户发送的JSON数据是否有效。验证器运行良好,但我无法捕获错误并将其发送到客户端。我知道在ValidationPipe
构造函数中有一个exeptionFactory
属性,但我仍然无法捕获错误,它仍然记录在控制台中。
[Nest] 11820 - 01/07/2023, 11:12:25 PM 错误 [WsExceptionsHandler] 错误的请求异常
BadRequestException: 错误的请求异常
这是一段代码
@SubscribeMessage(Stream.Transactions)
@UseGuards(JwtAuthGuard)
@UsePipes(new ValidationPipe())
handleTransactions(
clien: any,
@MessageBody() data: TransactionObject,
) {
let req = this.streamService.transaction(data)
return { event: Stream.Transactions, data: req }
}
英文:
I have a validation pipe that checks if a user-sent JSON data is valid. Validator is working great, but I can not catch the error and then send it to the client. I know about exeptionFactory
property in ValidationPipe
constructor, but I still can not catch an error and it still logs in the console.
[Nest] 11820 - 01/07/2023, 11:12:25 PM ERROR [WsExceptionsHandler] Bad Request Exception
BadRequestException: Bad Request Exception
Here is a code
@SubscribeMessage(Stream.Transactions)
@UseGuards(JwtAuthGuard)
@UsePipes(new ValidationPipe())
handleTransactions(
clien: any,
@MessageBody() data: TransactionObject,
) {
let req = this.streamService.transaction(data)
return { event: Stream.Transactions, data: req }
}
答案1
得分: 2
我认为你可以创建一个过滤器来获取错误并返回一些特定的数据。但你可以通过以下几种方式来实现:创建一个 Websocket 异常过滤器 来捕获错误,或者使用你在问题中提到的 exceptionFactory 来生成一个 WsException
并在过滤器中捕获它。
主要问题(如果我没记错的话)是管道不返回 WsException
,而是 BadRequestException
。
因此,要使用异常过滤器,当异常是 Bad Request
时,你可以使用以下代码:
@Catch(BadRequestException)
export class BadRequestExceptionsFilter extends BaseWsExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
// 在这里你有异常,可以检查数据
const wsException = new WsException(exception.getResponse())
super.catch(wsException, host);
}
}
注意,这段代码遵循了文档中的示例。
现在不仅可以获取和阅读异常,还可以创建一个正确的 WsException
。
要使用它,可以将 @UseFilters(BadRequestExceptionsFilter)
添加到你的网关中。
另一种方法是捕获 WS 和 HTTP 异常,并根据需要进行处理,类似于这个示例。思路是只捕获 HTTP 异常以获取 Bad Request
,这样你的期望上下文将始终是 WS
:
@Catch(WsException, HttpException)
export class WsAndHttpExceptionFilter {
public catch(exception: HttpException, host: ArgumentsHost) {
// 在这里你有异常,可以检查数据
const ctx = host.switchToWs()
const client = ctx.getClient() as WebSocket;
client.send(JSON.stringify({ /* ... */ }))
}
}
或者你也可以尝试创建一个 exceptionFactory
来返回 WsException
。
- 在装饰器中:
@UsePipes(new ValidationPipe({
exceptionFactory(validationErrors: ValidationError[] = []) {
// 这里是错误信息
if (this.isDetailedOutputDisabled) {
return new WsException();
}
const errors = this.flattenValidationErrors(validationErrors);
return new WsException(errors);
}
}))
请检查一下项目中的工厂是如何实现的,以及这段代码如何尝试遵循相同的方式来返回 WsException
。
- 或者在一个扩展
ValidationPipe
的类中:
@Injectable()
export class WSValidationPipe extends ValidationPipe {
createExceptionFactory() {
return (validationErrors: ValidationError[] = []) {
// 这里是错误信息
if (this.isDetailedOutputDisabled) {
return new WsException();
}
const errors = this.flattenValidationErrors(validationErrors);
return new WsException(errors);
}
}
}
顺便说一下,如果你想返回你想要的数据,也可以使用 @Catch(WsException)
(仅捕获这个更明确的异常):
@Catch(WsException)
export class WebsocketExceptionsFilter extends BaseWsExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToWs()
const client = ctx.getClient() as WebSocket;
const data = ctx.getData();
client.send(JSON.stringify({
event: 'error',
ok: false,
error: exception.getError(),
data: data // 或者你想要添加的任何内容
}))
}
}
我现在无法测试所有这些代码,但我已经使用了其中的一些片段,对我有用,希望对你有所帮助。
英文:
I think you can create a filter to get the error and return some specific data. But you can do it in a couple ways: Creating a Websocket exception filter to catch the error or use the exceptionFactory you mention in your question to generate a WsException
and catch into the filter.
The main problem (if I'm not wrong) is the pipe does not return a WsException
but a BadRequestException
.
So to use an exception filter, how the exception is Bad Request
, you can use this one:
@Catch(BadRequestException)
export class BadRequestExceptionsFilter extends BaseWsExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
// Here you have the exception and you can check the data
const wsException = new WsException(exception.getResponse())
super.catch(wsException, host);
}
}
Note how this code follows the documentation
And now not only you can get and read the exception but also you can create a properly WsException
.
To use this you can add @UseFilters(BadRequestExceptionsFilter)
into your gateway.
Another way is to catch WS and HTTP exceptions and handle properly you want, something similar to this example. The idea can be to catch the HTTP exception only to get Bad Request
so your desired context will be always WS
:
@Catch(WsException, HttpException)
export class WsAndHttpExceptionFilter {
public catch(exception: HttpException, host: ArgumentsHost) {
// Here you have the exception and you can check the data
const ctx = host.switchToWs()
const client = ctx.getClient() as WebSocket;
client.send(JSON.stringify({ /* ... */ }))
}
}
Or also you can try to create the exceptionFactory
to return the WsException
.
- Into the decorator:
@UsePipes(new ValidationPipe({
exceptionFactory(validationErrors: ValidationError[] = []) {
// Here are the errors
if (this.isDetailedOutputDisabled) {
return new WsException();
}
const errors = this.flattenValidationErrors(validationErrors);
return new WsException(errors);
}
}))
Check how factories are done into the project and how this code tries to follow the same way but returning WsException
.
- Or in a class extending
ValidationPipe
:
@Injectable()
export class WSValidationPipe extends ValidationPipe {
createExceptionFactory() {
return (validationErrors: ValidationError[] = []) {
// Here are the errors
if (this.isDetailedOutputDisabled) {
return new WsException();
}
const errors = this.flattenValidationErrors(validationErrors);
return new WsException(errors);
}
}
}
By the way, you can also @Catch(WsException)
(and only this exception which is clearer) once are thrown if it is util for you to return the data you want:
@Catch(WsException)
export class WebsocketExceptionsFilter extends BaseWsExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToWs()
const client = ctx.getClient() as WebSocket;
const data = ctx.getData();
client.send(JSON.stringify({
event: 'error',
ok: false,
error: exception.getError(),
data: data // Or whatever you want to add
}))
}
}
I can't test now all this code but I've used some of these snippets and works for me, hope it helps.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论