为什么抛出此错误会导致空白响应,而其他错误会起作用?
Why does throwing this error result in a blank response, while others work?
我正在使用 NestJS 做一个项目,在为组件开发服务和控制器时,我使用 try - catch 方法处理错误,然后抛出它们。但是,我遇到了一个我无法抛出的特定错误,因为它导致响应主体为空白,而其他的则有效。例如:
这是我的 upload.service.ts
:
中的一个(有效)函数
async saveFile(body, file) {
try {
const uploadRepository = getRepository(Upload);
const result = await uploadRepository.save({
// assign properties [...]
});
return result;
} catch (error) {
unlink(file.path);
console.log(error); // Output 1
throw new BadRequestException(error); // Response 1
}
}
所以当我故意发出错误请求时(通过不在请求正文中发送所需的值),我在控制台中得到了这个:
(输出 1)
QueryFailedError: null value in column "type" of relation "upload" violates not-null constraint
at new QueryFailedError (%PROJECT_DIRECTORY%\node_modules\typeorm\error\QueryFailedError.js:11:28)
at PostgresQueryRunner.<anonymous> (%PROJECT_DIRECTORY%\node_modules\typeorm\driver\postgres\PostgresQueryRunner.js:247:31)
at step (%PROJECT_DIRECTORY%\node_modules\typeorm\node_modules\tslib\tslib.js:141:27)
at Object.throw (%PROJECT_DIRECTORY%\node_modules\typeorm\node_modules\tslib\tslib.js:122:57)
at rejected (%PROJECT_DIRECTORY%\node_modules\typeorm\node_modules\tslib\tslib.js:113:69)
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
length: 393,
severity: 'ERROR',
code: '23502',
detail: 'Failing row contains (51, 15, 2021-03-23 10:52:59.763387, 2021-03-23 10:52:59.763387, example.pdf, application/pdf, uploads\e0f65f7ab43f1c226b37a9463f3a4745, null).',
[...]
}
并使用 Postman 在响应正文中 return 编辑正确的错误:
(Response 1)
{
"message": "null value in column \"type\" of relation \"upload\" violates not-null constraint",
"length": 393,
"name": "QueryFailedError",
"severity": "ERROR",
"code": "23502",
"detail": "Failing row contains (51, 15, 2021-03-23 10:52:59.763387, 2021-03-23 10:52:59.763387, example.pdf, application/pdf, uploads\e0f65f7ab43f1c226b37a9463f3a4745, null).",
[...]
}
现在,这是 upload.service.ts
中的另一个函数:
async readFile(res, fileId) {
try {
const uploadRepository = getRepository(Upload);
const found = await uploadRepository.findOne({ id: fileId });
res.download(found.path, found.originalName);
} catch (error) {
console.log(error); // Output 2
throw new BadRequestException(error); // Response 2
}
}
当我故意发出错误请求(通过发送一个 uploadRepository.findOne
找不到的不存在的 ID)时,我在控制台中得到了这个:
(输出 2)
TypeError: Cannot read property 'path' of undefined
at UploadsService.readFile (%PROJECT_DIRECTORY%\dist\src\components\uploads\uploads.service.js:52:32)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async %PROJECT_DIRECTORY%\node_modules\@nestjs\core\router\router-execution-context.js:46:28
at async %PROJECT_DIRECTORY%\node_modules\@nestjs\core\router\router-proxy.js:9:17
但是响应正文中的一个空白对象,尽管它正确地具有 400 状态代码,使用 Postman:
(响应 2)
{}
我可以看出前一个错误,如 console.log 输出所示,有一个具有更多属性的对象。但是,我不知道为什么我无法正确 return 后一个错误。我也试过:
throw new NotFoundException({ message: error });
throw new NotFoundException(JSON.stringify(error));
throw new NotFoundException(error.TypeError);
运气不好,因为他们在 message 键中显示了一个空对象。
所以,问题是:这些错误有何不同,发送后者的正确方法是什么?
这个有趣的问题让我深入了解了 NestJS 源代码。所以,这就是正在发生的事情。
在抛出传递给 TypeError
的 BadRequestException
之后(请注意,这来自 NodeJS,而不是 NestJS) BaseExceptionFilter
捕获错误并将其传递给 ExpressAdapter
(假设您使用的是快递)。在那里,on the following line,他们这样做:
return isObject(body) ? response.json(body) : response.send(String(body));
body
变量引用了TypeError
本身,是一个对象,所以response.json(body)
被执行了。
问题是,在 response.json
函数内部,传递给它的对象使用 JSON.stringify
获得 stringifed
。
由于 TypeError
没有可枚举的属性,因此您得到一个空对象字符串 {}
。
如果您想知道 为什么 也就是说,请查看此 SO-post。
因此,为了解决这个问题,您可以创建自己的错误对象而不是 TypeError
并将其传递给 BadRequestException
。
在收到 eol 的回答后,我想知道“我怎么才能看到一个对象的结构是什么”?所以我进入了 Object.getOwnPropertyNames() 方法,该方法“returns 所有属性的数组( 包括不可枚举的属性 除了那些使用符号)直接在给定对象中找到。"
添加 console.log(Object.getOwnPropertyNames(error));
后输出为 [ 'stack', 'message' ]
.
由于 message
属性 是一个字符串,最终起作用的是:
throw new NotFoundException(error.message);
我正在使用 NestJS 做一个项目,在为组件开发服务和控制器时,我使用 try - catch 方法处理错误,然后抛出它们。但是,我遇到了一个我无法抛出的特定错误,因为它导致响应主体为空白,而其他的则有效。例如:
这是我的 upload.service.ts
:
async saveFile(body, file) {
try {
const uploadRepository = getRepository(Upload);
const result = await uploadRepository.save({
// assign properties [...]
});
return result;
} catch (error) {
unlink(file.path);
console.log(error); // Output 1
throw new BadRequestException(error); // Response 1
}
}
所以当我故意发出错误请求时(通过不在请求正文中发送所需的值),我在控制台中得到了这个:
(输出 1)
QueryFailedError: null value in column "type" of relation "upload" violates not-null constraint
at new QueryFailedError (%PROJECT_DIRECTORY%\node_modules\typeorm\error\QueryFailedError.js:11:28)
at PostgresQueryRunner.<anonymous> (%PROJECT_DIRECTORY%\node_modules\typeorm\driver\postgres\PostgresQueryRunner.js:247:31)
at step (%PROJECT_DIRECTORY%\node_modules\typeorm\node_modules\tslib\tslib.js:141:27)
at Object.throw (%PROJECT_DIRECTORY%\node_modules\typeorm\node_modules\tslib\tslib.js:122:57)
at rejected (%PROJECT_DIRECTORY%\node_modules\typeorm\node_modules\tslib\tslib.js:113:69)
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
length: 393,
severity: 'ERROR',
code: '23502',
detail: 'Failing row contains (51, 15, 2021-03-23 10:52:59.763387, 2021-03-23 10:52:59.763387, example.pdf, application/pdf, uploads\e0f65f7ab43f1c226b37a9463f3a4745, null).',
[...]
}
并使用 Postman 在响应正文中 return 编辑正确的错误:
(Response 1)
{
"message": "null value in column \"type\" of relation \"upload\" violates not-null constraint",
"length": 393,
"name": "QueryFailedError",
"severity": "ERROR",
"code": "23502",
"detail": "Failing row contains (51, 15, 2021-03-23 10:52:59.763387, 2021-03-23 10:52:59.763387, example.pdf, application/pdf, uploads\e0f65f7ab43f1c226b37a9463f3a4745, null).",
[...]
}
现在,这是 upload.service.ts
中的另一个函数:
async readFile(res, fileId) {
try {
const uploadRepository = getRepository(Upload);
const found = await uploadRepository.findOne({ id: fileId });
res.download(found.path, found.originalName);
} catch (error) {
console.log(error); // Output 2
throw new BadRequestException(error); // Response 2
}
}
当我故意发出错误请求(通过发送一个 uploadRepository.findOne
找不到的不存在的 ID)时,我在控制台中得到了这个:
(输出 2)
TypeError: Cannot read property 'path' of undefined
at UploadsService.readFile (%PROJECT_DIRECTORY%\dist\src\components\uploads\uploads.service.js:52:32)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async %PROJECT_DIRECTORY%\node_modules\@nestjs\core\router\router-execution-context.js:46:28
at async %PROJECT_DIRECTORY%\node_modules\@nestjs\core\router\router-proxy.js:9:17
但是响应正文中的一个空白对象,尽管它正确地具有 400 状态代码,使用 Postman:
(响应 2)
{}
我可以看出前一个错误,如 console.log 输出所示,有一个具有更多属性的对象。但是,我不知道为什么我无法正确 return 后一个错误。我也试过:
throw new NotFoundException({ message: error });
throw new NotFoundException(JSON.stringify(error));
throw new NotFoundException(error.TypeError);
运气不好,因为他们在 message 键中显示了一个空对象。
所以,问题是:这些错误有何不同,发送后者的正确方法是什么?
这个有趣的问题让我深入了解了 NestJS 源代码。所以,这就是正在发生的事情。
在抛出传递给 TypeError
的 BadRequestException
之后(请注意,这来自 NodeJS,而不是 NestJS) BaseExceptionFilter
捕获错误并将其传递给 ExpressAdapter
(假设您使用的是快递)。在那里,on the following line,他们这样做:
return isObject(body) ? response.json(body) : response.send(String(body));
body
变量引用了TypeError
本身,是一个对象,所以response.json(body)
被执行了。
问题是,在 response.json
函数内部,传递给它的对象使用 JSON.stringify
获得 stringifed
。
由于 TypeError
没有可枚举的属性,因此您得到一个空对象字符串 {}
。
如果您想知道 为什么 也就是说,请查看此 SO-post。
因此,为了解决这个问题,您可以创建自己的错误对象而不是 TypeError
并将其传递给 BadRequestException
。
在收到 eol 的回答后,我想知道“我怎么才能看到一个对象的结构是什么”?所以我进入了 Object.getOwnPropertyNames() 方法,该方法“returns 所有属性的数组( 包括不可枚举的属性 除了那些使用符号)直接在给定对象中找到。"
添加 console.log(Object.getOwnPropertyNames(error));
后输出为 [ 'stack', 'message' ]
.
由于 message
属性 是一个字符串,最终起作用的是:
throw new NotFoundException(error.message);