在 Node.js 里,未捕获的错误容易引起内存泄漏、文件描述符泄漏等生产环境主要的问题。Domain 模块被设计用来解决这一问题,然而效果不佳。
由于不可能合理地处理所有未捕获的错误,目前最好的处理方案就是使程序崩溃。
未处理的 promise rejection (即未被 .catch()
处理) 在 Node.js 中也可能引起内存或文件描述符泄漏。unhandledRejection
不被推荐,未处理的 rejection 也不会抛出,因此还是可能会泄露。你应当使用如 make-promises-safe
的模块来确保未处理的 rejection 总能 被抛出。
假如你使用 promise,你应当同时给它们加上 .catch()
。
Fastify 遵循不全则无的原则,旨在精而优。因此,确保正确处理错误是开发者需要考虑的问题。
由于大部分的错误源于预期外的输入,因此我们推荐通过 JSON.schema 来验证输入数据。
在不影响性能的前提下,Fastify 尽可能多地捕捉未捕获的错误。这些错误包括:
- 同步路由中的错误。如
app.get('/', () => { throw new Error('kaboom') })
async
路由中的错误。如app.get('/', async () => { throw new Error('kaboom') })
上述错误都会被安全地捕捉,并移交给 Fastify 默认的错误处理函数,发送一个通用的 500 Internal Server Error
响应。
要自定义该行为,请见 setErrorHandler
。
在钩子的文档中提到:
假如在钩子执行过程中发生错误,只需把它传递给
done()
,Fastify 便会自动地关闭请求,并向用户发送合适的错误代码。
如果通过 setErrorHandler
自定义了一个错误函数,那么错误会被引导到那里,否则被引导到 Fastify 默认的错误函数中去。
自定义错误函数应该考虑以下几点:
-
你可以调用
reply.send(data)
,正如在常规路由中那样- object 会被序列化,并触发
preSerialization
钩子 (假如有定义的话) - string、buffer 及 stream 会被直接发送至客户端 (不会序列化),并附带上合适的 header。
- object 会被序列化,并触发
-
在错误函数里你可以抛出新的错误
- 错误 (新的错误,或被重新抛出的错误参数) 会触发
onError
钩子,并被发送给用户 - 在同一个钩子内,一个错误不会被触发两次。Fastify 会内在地监控错误的触发,以此避免在回复阶段无限循环地抛错 (在路由函数执行后)。
- 错误 (新的错误,或被重新抛出的错误参数) 会触发
无效的 url。
该 content type 的解析器已经被注册。
请求 body 大小超过限制。
可通过 Fastify 实例的 bodyLimit
属性改变大小限制。
content type 不能是一个空字符串。
请求 body 大小与 Content-Length 不一致。
该 content type 接收的处理函数无效。
收到的 media type 不支持 (例如,不存在合适的 Content-Type
解析器)。
提供的待解析类型不支持。只支持 string
和 buffer
。
Content-Type
应为一个字符串。
已存在同名的装饰器。
缺失依赖导致装饰器无法注册。
钩子的回调必须为函数。
钩子名称必须为字符串。
日志工具目标地址无效。仅接受 'stream'
或 'file'
作为目标地址。
状态码不为 204 时,Promise 的 payload 不能为 'undefined'。
响应已发送。
响应 payload 类型无效。只允许 string
或 Buffer
。
同 $id
的 schema 已经存在。
提供的 schema 没有 $id
属性。
用于序列化响应的 JSON schema 不合法。
用于校验路由的 JSON schema 不合法。
不能在 onError
钩子中调用 send
。
发生了未定义的错误。