localhost
GET
本页提供了一个更高级的指南,用于在 Elysia 中有效处理错误。
如果你还没有阅读 “生命周期 (onError)”,建议先阅读它。
在定义模式时,可以为每个字段提供自定义验证消息。
当验证失败时,该消息将原样返回。
import { Elysia } from 'elysia'
new Elysia().get('/:id', ({ params: { id } }) => id, {
params: t.Object({
id: t.Number({
error: 'id 必须是数字'
})
})
})
如果 id
字段验证失败,响应将返回 id 必须是数字
。
GET
从 schema.error
返回一个值将原样返回验证消息,但有时你也希望返回验证细节,比如字段名和期望类型。
你可以通过使用 validationDetail
来实现这一点。
import { Elysia, validationDetail } from 'elysia'
new Elysia().get('/:id', ({ params: { id } }) => id, {
params: t.Object({
id: t.Number({
error: validationDetail('id 必须是数字')
})
})
})
这将在响应中包含所有验证详情,比如字段名和期望类型。
GET
但是如果你计划在每个字段都使用 validationDetail
,手动添加会很麻烦。
你可以在 onError
钩子中自动处理验证详情。
new Elysia()
.onError(({ error, code }) => {
if (code === 'VALIDATION') return error.detail(error.message)
})
.get('/:id', ({ params: { id } }) => id, {
params: t.Object({
id: t.Number({
error: 'id 必须是数字'
})
})
})
.listen(3000)
这将为每个带有自定义消息的验证错误添加自定义验证详情。
默认情况下,如果 NODE_ENV
是 production
,Elysia 会省略所有验证详情。
这样做是为了防止泄露验证模式的敏感信息,比如字段名和期望类型,这可能被攻击者利用。
Elysia 只会返回验证失败的信息,而不包含任何详情。
{
"type": "validation",
"on": "body",
"found": {},
// 仅对自定义错误显示
"message": "x 必须是数字"
}
message
属性是可选的,默认省略,除非你在模式中提供了自定义错误消息。
Elysia 支持类型层级和实现层级的自定义错误。
默认情况下,Elysia 有一组内置错误类型,如 VALIDATION
、NOT_FOUND
,会自动缩小类型。
如果 Elysia 不认识该错误,错误代码将是 UNKNOWN
,默认状态码为 500
。
但你也可以通过 Elysia.error
添加带类型安全的自定义错误,它能帮助缩小错误类型,提供完整类型安全和自动补全,并支持自定义状态码,如下所示:
import { Elysia } from 'elysia'
class MyError extends Error {
constructor(public message: string) {
super(message)
}
}
new Elysia()
.error({
MyError
})
.onError(({ code, error }) => {
switch (code) {
// 自动补全
case 'MyError':
// 类型缩小
// 悬停查看 error 的类型为 `CustomError`
return error
}
})
.get('/:id', () => {
throw new MyError('Hello Error')
})
你也可以通过在自定义错误类中添加 status
属性,为你的自定义错误指定状态码。
import { Elysia } from 'elysia'
class MyError extends Error {
status = 418
constructor(public message: string) {
super(message)
}
}
当抛出该错误时,Elysia 会使用此状态码。
否则你也可以在 onError
钩子中手动设置状态码。
import { Elysia } from 'elysia'
class MyError extends Error {
constructor(public message: string) {
super(message)
}
}
new Elysia()
.error({
MyError
})
.onError(({ code, error, status }) => {
switch (code) {
case 'MyError':
return status(418, error.message)
}
})
.get('/:id', () => {
throw new MyError('Hello Error')
})
你也可以在自定义错误类中提供一个自定义的 toResponse
方法,当错误被抛出时返回自定义响应。
import { Elysia } from 'elysia'
class MyError extends Error {
status = 418
constructor(public message: string) {
super(message)
}
toResponse() {
return Response.json({
error: this.message,
code: this.status
}, {
status: 418
})
}
}
大多数错误处理可以通过抛出错误并在 onError
中处理完成。
但 status
可能会让人困惑,因为它既可以作为返回值也可以抛出错误。
根据你的具体需求,它可以是 返回 或 抛出 。
status
被 抛出,会被 onError
中间件捕获。status
被 返回,不会被 onError
中间件捕获。请看以下代码:
import { Elysia, file } from 'elysia'
new Elysia()
.onError(({ code, error, path }) => {
if (code === 418) return 'caught'
})
.get('/throw', ({ status }) => {
// 这会被 onError 捕获
throw status(418)
})
.get('/return', ({ status }) => {
// 这不会被 onError 捕获
return status(418)
})
GET