NESTJS异常滤镜弄乱错误阵列,如果来自验证pipe
因此,我使用验证管来验证我在Nestjs中的DTO,因此:
// auth.dto.ts
export class AuthDto {
@IsEmail()
@IsNotEmpty()
email: string;
}
没有例外过滤器,错误消息按预期工作。我将电子邮件字段留为空,然后收到一系列错误消息:
// Response - Message array, but no wrapper
{
"statusCode": 400,
"message": [
"email should not be empty",
"email must be an email"
],
"error": "Bad Request"
}
完美。现在,我想为错误消息实现包装器,因此我创建一个新的过滤器并将其添加到Bootstrap:
// main.ts
async function bootstrap() {
// ...
app.useGlobalFilters(new GlobalExceptionFilter());
}
bootstrap();
// global-exception.filter.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { Response } from 'express';
import { IncomingMessage } from 'http';
export const getStatusCode = <T>(exception: T): number => {
return exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
};
export const getErrorMessage = <T>(exception: T): string => {
return exception instanceof HttpException
? exception.message
: String(exception);
};
@Catch()
export class GlobalExceptionFilter<T> implements ExceptionFilter {
catch(exception: T, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<IncomingMessage>();
const statusCode = getStatusCode<T>(exception);
const message = getErrorMessage<T>(exception);
response.status(statusCode).json({
error: {
timestamp: new Date().toISOString(),
path: request.url,
statusCode,
message,
},
});
}
}
它对我的大多数错误都非常有用:
// Response - Good format (wrapped), single message expected
{
"error": {
"timestamp": "2022-05-11T19:54:59.093Z",
"path": "/auth/signup",
"statusCode": 400,
"message": "Email already in use"
}
}
但是当我从验证中获得验证时,它应该给我一个数组或一个数组或邮件如上所述,但它给出了此消息:
// Response - Wrapper: check, single message instead of array
{
"error": {
"timestamp": "2022-05-11T19:59:17.282Z",
"path": "/auth/signup",
"statusCode": 400,
"message": "Bad Request Exception" // it should be "message": ["not empty", "must be email"]
}
}
我的异常过滤器中的异常对象具有一个响应字段,其中包含消息数组:
// HttpException object inside the filter class
{
response: {
statusCode: 400,
message: [ 'email should not be empty', 'email must be an email' ],
error: 'Bad Request'
},
status: 400
}
但是exception.Response.message
不起作用,因为该字段为私人和打字稿引发错误:属性'响应'是私人的,只有在“ httpexception”类中访问。
你们中的任何一个知道我如何达到消息阵列,以便我可以格式化我的我错误响应正确?
编辑:对不起,很长的帖子!
So I use the ValidationPipe to validate my DTOs in NestJS, like this:
// auth.dto.ts
export class AuthDto {
@IsEmail()
@IsNotEmpty()
email: string;
}
Without the Exception filter the error message works as intended. I leave the email field empty and I receive an array of error messages:
// Response - Message array, but no wrapper
{
"statusCode": 400,
"message": [
"email should not be empty",
"email must be an email"
],
"error": "Bad Request"
}
Perfect. Now I want to implement a wrapper for the error messages, so I create a new filter and add it to to bootstrap:
// main.ts
async function bootstrap() {
// ...
app.useGlobalFilters(new GlobalExceptionFilter());
}
bootstrap();
// global-exception.filter.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { Response } from 'express';
import { IncomingMessage } from 'http';
export const getStatusCode = <T>(exception: T): number => {
return exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
};
export const getErrorMessage = <T>(exception: T): string => {
return exception instanceof HttpException
? exception.message
: String(exception);
};
@Catch()
export class GlobalExceptionFilter<T> implements ExceptionFilter {
catch(exception: T, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<IncomingMessage>();
const statusCode = getStatusCode<T>(exception);
const message = getErrorMessage<T>(exception);
response.status(statusCode).json({
error: {
timestamp: new Date().toISOString(),
path: request.url,
statusCode,
message,
},
});
}
}
It works great for most of my errors:
// Response - Good format (wrapped), single message expected
{
"error": {
"timestamp": "2022-05-11T19:54:59.093Z",
"path": "/auth/signup",
"statusCode": 400,
"message": "Email already in use"
}
}
But when I get a ValidationError from the ValidationPipe it should give me an array or messages like before, but it gives this message instead:
// Response - Wrapper: check, single message instead of array
{
"error": {
"timestamp": "2022-05-11T19:59:17.282Z",
"path": "/auth/signup",
"statusCode": 400,
"message": "Bad Request Exception" // it should be "message": ["not empty", "must be email"]
}
}
The exception object in my exception filter has a response field which contains the message array:
// HttpException object inside the filter class
{
response: {
statusCode: 400,
message: [ 'email should not be empty', 'email must be an email' ],
error: 'Bad Request'
},
status: 400
}
But exception.response.message
doesn't work, because the field is private and TypeScript throws an error:Property 'response' is private and only accessible within class 'HttpException'.
Does any of you know how could I reach the message array, so I could format my error response properly?
EDIT: Sorry for the long post!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
AS @tobias-s 评论说,有一个解决方案,解决了问题:
As @tobias-s commented, there's a workaround, which solved the problem:
当您使用
@catch
装饰器时,您是否可以获得httpexception
not,因此我们需要对其进行评估。让我们创建一个接口“ parse” nest.js内置
httpexception
类响应:现在我们可以对其进行处理:
except.getResponse()
可以是字符串或对象,那是因为我们将其处理为消息:当然,任何
。As you are using
@Catch
decorator, you could get aHttpException
or not, so we need to evaluate it.Let's create an interface to "parse" Nest.js built-in
HttpException
class response:Now we can process it:
exception.getResponse()
can be a string or an object, that's because we handle it asmessage: any
of course.