我如何 return 来自环回 4 中控制器的错误?
How do I return an error from a Controller in Loopback 4?
我有一个控制器方法
// ... inside a controller class
@get('/error', {})
async error() {
throw new Error("This is the error text");
}
我从这个错误前端得到的响应是:
{
"error": {
"statusCode": 500,
"message": "Internal Server Error"
}
}
我希望错误是:
{
"error": {
"statusCode": 500,
"message": "This is the error text"
}
}
如何 return Loopback 4 中的控制器出错?
来自 LoopBack 团队的问候
在您的控制器或存储库中,您应该完全按照问题中所示抛出错误。
现在,当 LoopBack 捕获到错误时,它会调用 reject
操作来处理错误。 reject
的内置实现通过 console.error
和 returns 带有 4xx/5xx 错误代码和描述错误的响应正文的 HTTP 响应记录消息。
默认情况下,LoopBack 隐藏 HTTP 响应中的实际错误消息。这是一项安全措施,可防止服务器泄露潜在的敏感数据(无法打开的文件路径、无法访问的后端服务的 IP 地址)。
在后台,我们使用 strong-error-handler 将错误对象转换为 HTTP 响应。该模块提供两种模式:
- 生产模式(默认):5xx 错误不包含任何附加信息,4xx 错误包含部分信息。
- 调试模式 (
debug: true
):响应中包含所有错误详细信息,包括完整的堆栈跟踪。
可以通过将以下行添加到应用程序构造函数来启用调试模式:
this.bind(RestBindings.ERROR_WRITER_OPTIONS).to({debug: true});
在我们的文档中了解更多信息:Sequence >> Handling errors
或者,您可以实现自己的错误处理程序并将其绑定为序列操作 reject
。请参阅我们的文档中的 Customizing sequence actions。
export class MyRejectProvider implements Provider<Reject> {
constructor(
@inject(RestBindings.SequenceActions.LOG_ERROR)
protected logError: LogError,
@inject(RestBindings.ERROR_WRITER_OPTIONS, {optional: true})
protected errorWriterOptions?: ErrorWriterOptions,
) {}
value(): Reject {
return (context, error) => this.action(context, error);
}
action({request, response}: HandlerContext, error: Error) {
const err = <HttpError>error;
const statusCode = err.statusCode || err.status || 500;
const body = // convert err to plain data object
res.statusCode = statusCode;
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.end(JSON.stringify(body), 'utf-8');
this.logError(error, statusCode, request);
}
}
对于我的情况,我在 sequence.ts
文件中找到了一个 catch
。在 catch 中,它检查错误的状态代码是否为 4xx,如果不是,它只返回一个匿名的 500。
这是我正在寻找的执行逻辑的代码:
// sequence.ts
...
} catch (err) {
console.log(err);
let code: string = (err.code || 500).toString();
if (code.length && code[0] === '4') {
response.status(Number(code) || 500);
return this.send(response, {
error: {
message: err.message,
name: err.name || 'UnknownError',
statusCode: code
}
});
}
return this.reject(context, err);
}
...
这是告诉它做什么的方法:
// ... inside a controller class
@get('/error', {})
async error() {
throw {
code: 400,
message: "This is the error text",
name: "IntentionalError"
}
}
如果你只想显示错误信息,你只需扩展 Error 对象并像下面那样抛出它。 (环回文档无论如何都没有提到这一点)
避免使用 5xx 错误并使用 4xx 错误向用户显示一些重要的事情是最佳实践,因此 Loopback4 是这样实现的。
class NotFound extends Error {
statusCode: number
constructor(message: string) {
super(message)
this.statusCode = 404
}
}
...
if (!await this.userRepository.exists(id)) {
throw new NotFound('user not found')
}
为了抛出自定义验证错误,我使用了这个方法:
private static createError(msg: string, name?: string): HttpErrors.HttpError {
const error = new HttpErrors['422'](msg);
error.name = name ?? this.name;
return error;
}
此处的捕获错误示例是针对 defaultSequence 的,覆盖了 handle 方法。
但是现在的应用程序模板使用 MiddlewareSequence。
所以这里是例子,如何修改中间件序列中的响应,你可以使用这个例子:
import { Middleware, MiddlewareContext } from '@loopback/rest';
export const ErrorMiddleware: Middleware = async (middlewareCtx: MiddlewareContext, next) => {
// const {response} = middlewareCtx;
try {
// Proceed with next middleware
return await next();
} catch (err) {
// Catch errors from downstream middleware
// How to catch specific error and how to send custom error response:
if (HttpErrors.isHttpError(err) || (err as HttpErrors.HttpError).statusCode) {
const code: string = (err.statusCode || 500).toString();
if (code.length && code[0] === '4') {
response.status(Number(code) || 500);
return response.send({
error: {
message: err.message,
name: err.name || 'UnknownError',
statusCode: code
}
});
}
}
throw err;
}
};
并在application.ts
中注册中间件
this.middleware(ErrorMiddleware);
我有一个控制器方法
// ... inside a controller class
@get('/error', {})
async error() {
throw new Error("This is the error text");
}
我从这个错误前端得到的响应是:
{ "error": { "statusCode": 500, "message": "Internal Server Error" } }
我希望错误是:
{ "error": { "statusCode": 500, "message": "This is the error text" } }
如何 return Loopback 4 中的控制器出错?
来自 LoopBack 团队的问候
在您的控制器或存储库中,您应该完全按照问题中所示抛出错误。
现在,当 LoopBack 捕获到错误时,它会调用 reject
操作来处理错误。 reject
的内置实现通过 console.error
和 returns 带有 4xx/5xx 错误代码和描述错误的响应正文的 HTTP 响应记录消息。
默认情况下,LoopBack 隐藏 HTTP 响应中的实际错误消息。这是一项安全措施,可防止服务器泄露潜在的敏感数据(无法打开的文件路径、无法访问的后端服务的 IP 地址)。
在后台,我们使用 strong-error-handler 将错误对象转换为 HTTP 响应。该模块提供两种模式:
- 生产模式(默认):5xx 错误不包含任何附加信息,4xx 错误包含部分信息。
- 调试模式 (
debug: true
):响应中包含所有错误详细信息,包括完整的堆栈跟踪。
可以通过将以下行添加到应用程序构造函数来启用调试模式:
this.bind(RestBindings.ERROR_WRITER_OPTIONS).to({debug: true});
在我们的文档中了解更多信息:Sequence >> Handling errors
或者,您可以实现自己的错误处理程序并将其绑定为序列操作 reject
。请参阅我们的文档中的 Customizing sequence actions。
export class MyRejectProvider implements Provider<Reject> {
constructor(
@inject(RestBindings.SequenceActions.LOG_ERROR)
protected logError: LogError,
@inject(RestBindings.ERROR_WRITER_OPTIONS, {optional: true})
protected errorWriterOptions?: ErrorWriterOptions,
) {}
value(): Reject {
return (context, error) => this.action(context, error);
}
action({request, response}: HandlerContext, error: Error) {
const err = <HttpError>error;
const statusCode = err.statusCode || err.status || 500;
const body = // convert err to plain data object
res.statusCode = statusCode;
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.end(JSON.stringify(body), 'utf-8');
this.logError(error, statusCode, request);
}
}
对于我的情况,我在 sequence.ts
文件中找到了一个 catch
。在 catch 中,它检查错误的状态代码是否为 4xx,如果不是,它只返回一个匿名的 500。
这是我正在寻找的执行逻辑的代码:
// sequence.ts
...
} catch (err) {
console.log(err);
let code: string = (err.code || 500).toString();
if (code.length && code[0] === '4') {
response.status(Number(code) || 500);
return this.send(response, {
error: {
message: err.message,
name: err.name || 'UnknownError',
statusCode: code
}
});
}
return this.reject(context, err);
}
...
这是告诉它做什么的方法:
// ... inside a controller class
@get('/error', {})
async error() {
throw {
code: 400,
message: "This is the error text",
name: "IntentionalError"
}
}
如果你只想显示错误信息,你只需扩展 Error 对象并像下面那样抛出它。 (环回文档无论如何都没有提到这一点)
避免使用 5xx 错误并使用 4xx 错误向用户显示一些重要的事情是最佳实践,因此 Loopback4 是这样实现的。
class NotFound extends Error {
statusCode: number
constructor(message: string) {
super(message)
this.statusCode = 404
}
}
...
if (!await this.userRepository.exists(id)) {
throw new NotFound('user not found')
}
为了抛出自定义验证错误,我使用了这个方法:
private static createError(msg: string, name?: string): HttpErrors.HttpError {
const error = new HttpErrors['422'](msg);
error.name = name ?? this.name;
return error;
}
此处的捕获错误示例是针对 defaultSequence 的,覆盖了 handle 方法。 但是现在的应用程序模板使用 MiddlewareSequence。
所以这里是例子,如何修改中间件序列中的响应,你可以使用这个例子:
import { Middleware, MiddlewareContext } from '@loopback/rest';
export const ErrorMiddleware: Middleware = async (middlewareCtx: MiddlewareContext, next) => {
// const {response} = middlewareCtx;
try {
// Proceed with next middleware
return await next();
} catch (err) {
// Catch errors from downstream middleware
// How to catch specific error and how to send custom error response:
if (HttpErrors.isHttpError(err) || (err as HttpErrors.HttpError).statusCode) {
const code: string = (err.statusCode || 500).toString();
if (code.length && code[0] === '4') {
response.status(Number(code) || 500);
return response.send({
error: {
message: err.message,
name: err.name || 'UnknownError',
statusCode: code
}
});
}
}
throw err;
}
};
并在application.ts
中注册中间件this.middleware(ErrorMiddleware);