异常处理
AdonisJS 使用异常进行流控制。这意味着,我们宁愿引发异常,然后处理它们以返回适当的响应,而不是编写太多的条件。例如:
我们更喜欢这样写代码#
在以下示例中,如果用户未登录,auth.authenticate
方法将引发异常。异常可以自行处理并返回适当的响应。
Route.get('dashboard', async ({ auth, response }) => {
await auth.authenticate()
// 业务逻辑
})
提示:不要将所有不符合要求的条件都转化为异常,建议只转换那些会导致请求中止的条件。
而不是编写以下代码#
Route.get('dashboard', async ({ auth, response }) => {
if (!auth.isLoggedIn) {
return response.status(401).send('Unauthenticated')
}
// 业务逻辑
})
全局处理异常#
HTTP 请求期间引发的异常被转发到存储在 app/Exceptions/Handler.ts
文件中。
// app/Exceptions/Handler.ts 文件
import Logger from '@ioc:Adonis/Core/Logger'
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
export default class ExceptionHandler extends HttpExceptionHandler {
protected statusPages = {
'404': 'errors/not-found',
'500..599': 'errors/server-error',
}
constructor() {
super(Logger)
}
}
handle
方法负责处理异常并将其转换为响应。 因此,可以让父类 (HttpExceptionHandler) 来处理错误,或者自定义 handle
方法来处理这些错误。
import Logger from '@ioc:Adonis/Core/Logger'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
export default class ExceptionHandler extends HttpExceptionHandler {
protected statusPages = {
'404': 'errors/not-found',
'500..599': 'errors/server-error',
}
constructor() {
super(Logger)
}
public async handle(error: any, ctx: HttpContextContract) {
/**
* 自行处理验证异常
*/
if (error.code === 'E_VALIDATION_FAILURE') {
return ctx.response.status(422).send(error.messages)
}
/**
* 将其余异常转发给父类
*/
return super.handle(error, ctx)
}
}
错误报告#
除了 handle 方法,您还可以实现 report
方法来将异常报告给日志记录或错误监控服务。
report
方法的默认实现使用 logger 来报告异常。
- 使用
logger.error
方法记录错误代码>= 500
的异常。 - 使用
logger.warn
方法记录错误代码为>= 400
的异常。 - 使用
logger.info
方法记录所有其他异常。
注:HTTP 响应不等待报告方法完成。也就是说,report 方法是在后台执行的。
如果需要,您可以覆盖 report
方法,如下例所示。
import Logger from '@ioc:Adonis/Core/Logger'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
export default class ExceptionHandler extends HttpExceptionHandler {
protected statusPages = {
'404': 'errors/not-found',
'500..599': 'errors/server-error',
}
constructor() {
super(Logger)
}
// highlight-start
public async report(error: any, ctx: HttpContextContract) {
if (!this.shouldReport(error)) {
return
}
if (typeof error.report === 'function') {
error.report(error, ctx)
return
}
someReportingService.report(error.message)
}
// highlight-end
}
报告上下文#
可以实现 context
方法以在报告错误时提供额外的数据。默认情况下,上下文包括当前请求 ID。
import Logger from '@ioc:Adonis/Core/Logger'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
export default class ExceptionHandler extends HttpExceptionHandler {
protected context(ctx: HttpContextContract) {
return {
userId: ctx.auth.user?.id
}
}
}
HTTP 异常处理程序#
以下功能仅在全局异常处理程序扩展 HttpExceptionHandler 类时可用。如果你决定不从此类扩展,则以下功能将不起作用。
页面状态#
异常处理程序上的 statusPages
页面属性允许将 Edge 模板与一系列错误状态代码相关联。
在以下示例中,所有 404 错误将呈现 errors/not-found.edge
模板,500 - 599 范围内的错误将呈现 errors/server-error.edge
模板。
import Logger from '@ioc:Adonis/Core/Logger'
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
export default class ExceptionHandler extends HttpExceptionHandler {
// highlight-start
protected statusPages = {
'404': 'errors/not-found',
'500..599': 'errors/server-error',
}
// highlight-end
constructor() {
super(Logger)
}
}
-
仅当 HTTP 请求
Accept
未设置为application/json
时,才会呈现状态页面。 -
T 状态页面在开发过程中被禁用。但是,您可以使用
disableStatusPagesInDevelopment
标志来启用它们。export default class ExceptionHandler extends HttpExceptionHandler { protected disableStatusPagesInDevelopment = false }
禁用某些异常的报告#
您可以通过将某些异常添加到 ignoreCodes
或 ignoreStatuses
属性中来忽略报告的某些异常。
import Logger from '@ioc:Adonis/Core/Logger'
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
export default class ExceptionHandler extends HttpExceptionHandler {
// highlight-start
protected ignoreCodes = ['E_ROUTE_NOT_FOUND']
protected ignoreStatuses = [404, 422, 403, 401]
// highlight-end
constructor() {
super(Logger)
}
}
自定义异常#
可以通过执行以下 Ace 命令来创建自定义异常。
node ace make:exception UnAuthorized
# 创建: app/Exceptions/UnAuthorizedException.ts
接下来,导入并引发异常,如下所示。
import UnAuthorized from 'App/Exceptions/UnAuthorizedException'
const message = 'You are not authorized'
const status = 403
const errorCode = 'E_UNAUTHORIZED'
throw new UnAuthorized(message, status, errorCode)
你可以通过在异常类上实现 handle
方法来自行处理此异常。
// app/Exceptions/UnAuthorizedException.ts 文件
import { Exception } from '@adonisjs/core/build/standalone'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class UnAuthorizedException extends Exception {
public async handle(error: this, ctx: HttpContextContract) {
ctx.response.status(error.status).send(error.message)
}
}
或者,你可以实现 report
方法将异常记录到日志,或错误报告服务。
// app/Exceptions/UnAuthorizedException.ts 文件
import { Exception } from '@adonisjs/core/build/standalone'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class UnAuthorizedException extends Exception {
public report(error: this, ctx: HttpContextContract) {
reportingService.report(error.message)
}
}
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。