异常处理
在 HTTP 请求期间引发的异常由 ./app/exceptions/handler.ts 文件中定义的 HttpExceptionHandler 处理。在此文件中,你可以决定如何将异常转换为响应,以及如何使用日志记录器记录它们或将它们报告给外部日志提供者。
HttpExceptionHandler 扩展自 ExceptionHandler 类,该类完成处理错误的所有繁重工作,并为你提供高级 API 来调整报告和渲染行为。
import app from '@adonisjs/core/services/app'
import { HttpContext, ExceptionHandler } from '@adonisjs/core/http'
export default class HttpExceptionHandler extends ExceptionHandler {
protected debug = !app.inProduction
protected renderStatusPages = app.inProduction
async handle(error: unknown, ctx: HttpContext) {
return super.handle(error, ctx)
}
async report(error: unknown, ctx: HttpContext) {
return super.report(error, ctx)
}
}将错误处理程序分配给服务器
错误处理程序在 start/kernel.ts 文件中注册到 AdonisJS HTTP 服务器。我们使用 package.json 文件中定义的 #exceptions 别名延迟导入 HTTP 处理程序。
server.errorHandler(() => import('#exceptions/handler'))处理异常
异常由异常处理程序类上的 handle 方法处理。默认情况下,在处理错误时执行以下步骤。
- 检查错误实例是否有
handle方法。如果有,调用 error.handle 方法并返回其响应。 - 检查是否为
error.status状态码定义了状态页面。如果有,渲染状态页面。 - 否则,使用内容协商渲染器渲染异常。
如果你想以不同方式处理特定异常,可以在 handle 方法中执行此操作。确保使用 ctx.response.send 方法发送响应,因为 handle 方法的返回值会被丢弃。
import { errors } from '@vinejs/vine'
export default class HttpExceptionHandler extends ExceptionHandler {
async handle(error: unknown, ctx: HttpContext) {
if (error instanceof errors.E_VALIDATION_ERROR) {
ctx.response.status(422).send(error.messages)
return
}
return super.handle(error, ctx)
}
}状态页面
状态页面是你想要为给定状态码或状态码范围渲染的模板集合。
状态码范围可以定义为字符串表达式。开始和结束状态码用两个点 (..) 分隔。
如果你正在创建 JSON 服务器,可能不需要状态页面。
import { StatusPageRange, StatusPageRenderer } from '@adonisjs/http-server/types'
export default class HttpExceptionHandler extends ExceptionHandler {
protected statusPages: Record<StatusPageRange, StatusPageRenderer> = {
'404': (_, { view }) => view.render('errors/not-found'),
'500..599': (_, { view }) => view.render('errors/server-error')
}
}调试模式
内容协商渲染器处理未自行处理且未转换为状态页面的异常。
内容协商渲染器支持调试模式。它们可以在调试模式下使用 Youch npm 包解析和美化打印错误。
你可以使用异常处理程序类上的 debug 属性切换调试模式。但是,建议在生产环境中关闭调试模式,因为它会暴露有关应用程序的敏感信息。
export default class HttpExceptionHandler extends ExceptionHandler {
protected debug = !app.inProduction
}报告异常
异常处理程序类上的 report 方法处理异常的报告。
该方法将错误作为第一个参数接收,将 HTTP 上下文作为第二个参数接收。你不应该从 report 方法写入响应,只能使用上下文读取请求信息。
记录异常
默认情况下,所有异常都使用日志记录器报告。
- 状态码在
400..499范围内的异常以warning级别记录。 - 状态码
>=500的异常以error级别记录。 - 所有其他异常以
info级别记录。
你可以通过从 context 方法返回对象来向日志消息添加自定义属性。
export default class HttpExceptionHandler extends ExceptionHandler {
protected context(ctx: HttpContext) {
return {
requestId: ctx.requestId,
userId: ctx.auth.user?.id,
ip: ctx.request.ip(),
}
}
}忽略状态码
你可以通过 ignoreStatuses 属性定义状态码数组来忽略异常的报告。
export default class HttpExceptionHandler extends ExceptionHandler {
protected ignoreStatuses = [
401,
400,
422,
403,
]
}忽略错误
你还可以通过定义要忽略的错误代码或错误类数组来忽略异常。
import { errors } from '@adonisjs/core'
import { errors as sessionErrors } from '@adonisjs/session'
export default class HttpExceptionHandler extends ExceptionHandler {
protected ignoreCodes = [
'E_ROUTE_NOT_FOUND',
'E_INVALID_SESSION'
]
}可以使用 ignoreExceptions 属性忽略异常类数组。
import { errors } from '@adonisjs/core'
import { errors as sessionErrors } from '@adonisjs/session'
export default class HttpExceptionHandler extends ExceptionHandler {
protected ignoreExceptions = [
errors.E_ROUTE_NOT_FOUND,
sessionErrors.E_INVALID_SESSION,
]
}自定义异常
你可以使用 make:exception ace 命令创建异常类。异常扩展自 @adonisjs/core 包中的 Exception 类。
另请参阅:Make exception 命令
node ace make:exception UnAuthorizedimport { Exception } from '@adonisjs/core/exceptions'
export default class UnAuthorizedException extends Exception {}你可以通过创建它的新实例来引发异常。引发异常时,可以为异常分配自定义错误代码和状态码。
import UnAuthorizedException from '#exceptions/unauthorized_exception'
throw new UnAuthorizedException('你未被授权', {
status: 403,
code: 'E_UNAUTHORIZED'
})错误和状态码也可以定义为异常类上的静态属性。如果抛出异常时未定义自定义值,将使用静态值。
import { Exception } from '@adonisjs/core/exceptions'
export default class UnAuthorizedException extends Exception {
static status = 403
static code = 'E_UNAUTHORIZED'
}定义 handle 方法
要自行处理异常,你可以在异常类上定义 handle 方法。此方法应使用 ctx.response.send 方法将错误转换为 HTTP 响应。
error.handle 方法将错误实例作为第一个参数,HTTP 上下文作为第二个参数。
import { Exception } from '@adonisjs/core/exceptions'
import { HttpContext } from '@adonisjs/core/http'
export default class UnAuthorizedException extends Exception {
async handle(error: this, ctx: HttpContext) {
ctx.response.status(error.status).send(error.message)
}
}定义 report 方法
你可以在异常类上实现 report 方法来自行处理异常报告。report 方法将错误实例作为第一个参数,HTTP 上下文作为第二个参数。
import { Exception } from '@adonisjs/core/exceptions'
import { HttpContext } from '@adonisjs/core/http'
export default class UnAuthorizedException extends Exception {
async report(error: this, ctx: HttpContext) {
ctx.logger.error({ err: error }, error.message)
}
}缩小错误类型
框架核心和其他官方包导出它们引发的异常。你可以使用 instanceof 检查来验证错误是否是特定异常的实例。例如:
import { errors } from '@adonisjs/core'
try {
router.builder().make('articles.index')
} catch (error: unknown) {
if (error instanceof errors.E_CANNOT_LOOKUP_ROUTE) {
// 处理错误
}
}已知错误
请查看异常参考指南以查看已知错误列表。