跳至主要内容
版本: 最新版本 (v5.0.x)

错误

错误

目录

Node.js 中的错误处理

未捕获的错误

在 Node.js 中,未捕获的错误可能会导致内存泄漏、文件描述符泄漏以及其他主要的生产问题。 是解决此问题的失败尝试。

鉴于无法明智地处理所有未捕获的错误,处理它们的最佳方法是崩溃

捕获 Promise 中的错误

如果您使用的是 promise,则应同步附加 .catch() 处理程序。

Fastify 中的错误

Fastify 遵循全有或全无的方法,并力求尽可能精简和优化。开发人员负责确保正确处理错误。

输入数据中的错误

大多数错误都是由于意外的输入数据导致的,因此我们建议根据 JSON 模式验证您的输入数据

在 Fastify 中捕获未捕获的错误

Fastify 尝试在不影响性能的情况下捕获尽可能多的未捕获错误。这包括

  1. 同步路由,例如 app.get('/', () => { throw new Error('kaboom') })
  2. async 路由,例如 app.get('/', async () => { throw new Error('kaboom') })

在这两种情况下,错误都将被安全地捕获并路由到 Fastify 的默认错误处理程序,以获取通用的 500 内部服务器错误响应。

要自定义此行为,您应该使用setErrorHandler

Fastify 生命周期钩子中的错误和自定义错误处理程序

来自钩子文档

如果在执行钩子期间发生错误,只需将其传递给 done(),Fastify 将自动关闭请求并将相应的错误代码发送给用户。

当通过setErrorHandler定义了自定义错误处理程序时,自定义错误处理程序将接收传递给 done() 回调(或通过其他支持的自动错误处理机制)的错误。如果 setErrorHandler 已多次使用以定义多个处理程序,则错误将被路由到在错误封装上下文中定义的最优先的处理程序。错误处理程序是完全封装的,因此插件中的 setErrorHandler 调用将限制错误处理程序到该插件的上下文。

根错误处理程序是 Fastify 的通用错误处理程序。此错误处理程序将使用 Error 对象中的标头和状态代码(如果存在)。如果提供了自定义错误处理程序,则不会自动设置标头和状态代码。

在您的自定义错误处理程序中需要注意的一些事项

  • 您可以 reply.send(data),其行为与常规路由处理程序中的行为相同

    • 对象被序列化,如果已定义,则触发 preSerialization 生命周期钩子
    • 字符串、缓冲区和流被发送到客户端,并带有相应的标头(无序列化)
  • 您可以在自定义错误处理程序中抛出一个新的错误 - 错误(新错误或重新抛出的接收到的错误参数) - 将调用父 errorHandler

    • onError 钩子将仅为第一个抛出的错误触发一次。
    • 生命周期钩子不会触发两次错误 - Fastify 在内部监视错误调用,以避免在生命周期的响应阶段(路由处理程序之后的阶段)中抛出错误时出现无限循环。

当通过setErrorHandler使用 Fastify 的自定义错误处理时,您应该了解错误如何在自定义错误处理程序和默认错误处理程序之间传播。

如果插件的错误处理程序重新抛出一个错误,并且该错误不是 Error 的实例(如以下示例中的 /bad 路由中所示),它将不会传播到父上下文错误处理程序。相反,它将被默认错误处理程序捕获。

为了确保一致的错误处理,建议抛出 Error 的实例。例如,在以下示例中,将 /bad 路由中的 throw 'foo' 替换为 throw new Error('foo') 可确保错误按预期通过自定义错误处理链传播。此做法有助于避免在 Fastify 中使用自定义错误处理时出现潜在的陷阱。

例如

const Fastify = require('fastify')

// Instantiate the framework
const fastify = Fastify({
logger: true
})

// Register parent error handler
fastify.setErrorHandler((error, request, reply) => {
reply.status(500).send({ ok: false })
})

fastify.register((app, options, next) => {
// Register child error handler
fastify.setErrorHandler((error, request, reply) => {
throw error
})

fastify.get('/bad', async () => {
// Throws a non-Error type, 'bar'
throw 'foo'
})

fastify.get('/good', async () => {
// Throws an Error instance, 'bar'
throw new Error('bar')
})

next()
})

// Run the server
fastify.listen({ port: 3000 }, function (err, address) {
if (err) {
fastify.log.error(err)
process.exit(1)
}
// Server is listening at ${address}
})

Fastify 错误代码

您可以访问 errorCodes 进行映射

// ESM
import { errorCodes } from 'fastify'

// CommonJs
const errorCodes = require('fastify').errorCodes

例如

const Fastify = require('fastify')

// Instantiate the framework
const fastify = Fastify({
logger: true
})

// Declare a route
fastify.get('/', function (request, reply) {
reply.code('bad status code').send({ hello: 'world' })
})

fastify.setErrorHandler(function (error, request, reply) {
if (error instanceof Fastify.errorCodes.FST_ERR_BAD_STATUS_CODE) {
// Log error
this.log.error(error)
// Send error response
reply.status(500).send({ ok: false })
} else {
// fastify will use parent error handler to handle this
reply.send(error)
}
})

// Run the server!
fastify.listen({ port: 3000 }, function (err, address) {
if (err) {
fastify.log.error(err)
process.exit(1)
}
// Server is now listening on ${address}
})

下表列出了 Fastify 使用的所有错误代码。

代码描述如何解决讨论
FST_ERR_NOT_FOUND404 未找到-#1168
FST_ERR_OPTIONS_NOT_OBJFastify 选项指定错误。Fastify 选项应为对象。#4554
FST_ERR_QSP_NOT_FNQueryStringParser 指定错误。QueryStringParser 选项应为函数。#4554
FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FNSchemaController.bucket 指定错误。SchemaController.bucket 选项应为函数。#4554
FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FNSchemaErrorFormatter 选项指定错误。SchemaErrorFormatter 选项应为非异步函数。#4554
FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJajv.customOptions 指定错误。ajv.customOptions 选项应为对象。#4554
FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARRajv.plugins 选项指定错误。ajv.plugins 选项应为数组。#4554
FST_ERR_CTP_ALREADY_PRESENT此内容类型的解析器已注册。使用不同的内容类型或删除已注册的解析器。#1168
FST_ERR_CTP_INVALID_TYPEContent-Type 指定错误Content-Type 应为字符串。#1168
FST_ERR_CTP_EMPTY_TYPEContent-Type 为空字符串。Content-Type 不能为空字符串。#1168
FST_ERR_CTP_INVALID_HANDLER内容类型的处理程序无效。使用不同的处理程序。#1168
FST_ERR_CTP_INVALID_PARSE_TYPE提供的解析类型不受支持。接受的值为 stringbuffer#1168
FST_ERR_CTP_BODY_TOO_LARGE请求主体大于提供的限制。在 Fastify 服务器实例设置中增加限制:bodyLimit#1168
FST_ERR_CTP_INVALID_MEDIA_TYPE接收到的媒体类型不受支持(即没有合适的 Content-Type 解析器)。使用不同的内容类型。#1168
FST_ERR_CTP_INVALID_CONTENT_LENGTH请求主体大小与 Content-Length 不匹配。检查请求主体大小和 Content-Length 标头。#1168
FST_ERR_CTP_EMPTY_JSON_BODY当内容类型设置为 application/json 时,主体不能为空。检查请求主体。#1253
FST_ERR_CTP_INSTANCE_ALREADY_STARTEDFastify 已经启动。

-#4554
FST_ERR_INSTANCE_ALREADY_LISTENINGFastify 实例已经在监听。-#4554
FST_ERR_DEC_ALREADY_PRESENT已经注册了相同名称的装饰器。使用不同的装饰器名称。#1168
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE装饰器的依赖项必须为 Array 类型。使用数组作为依赖项。#3090
FST_ERR_DEC_MISSING_DEPENDENCY由于缺少依赖项,无法注册装饰器。注册缺少的依赖项。#1168
FST_ERR_DEC_AFTER_START无法在启动后添加装饰器。在启动服务器之前添加装饰器。#2128
FST_ERR_DEC_REFERENCE_TYPE装饰器不能是引用类型。使用 getter/setter 接口定义装饰器,或使用钩子定义一个空装饰器。#5462
FST_ERR_HOOK_INVALID_TYPE钩子名称必须是字符串。使用字符串作为钩子名称。#1168
FST_ERR_HOOK_INVALID_HANDLER钩子回调必须是函数。使用函数作为钩子回调。#1168
FST_ERR_HOOK_INVALID_ASYNC_HANDLER异步函数的参数过多。异步钩子不应使用 done 参数。从异步钩子中移除 done 参数。#4367
FST_ERR_HOOK_NOT_SUPPORTED不支持此钩子。使用受支持的钩子。#4554
FST_ERR_MISSING_MIDDLEWARE您必须注册一个用于处理中间件的插件,访问 Middleware 获取更多信息。注册一个用于处理中间件的插件。#2014
FST_ERR_HOOK_TIMEOUT钩子的回调超时。增加钩子的超时时间。#3106
FST_ERR_LOG_INVALID_DESTINATION日志记录器不接受指定的目的地。使用 'stream''file' 作为目的地。#1168
FST_ERR_LOG_INVALID_LOGGER日志记录器应包含以下所有方法:'info''error''debug''fatal''warn''trace''child'使用包含所有必需方法的日志记录器。#4520
FST_ERR_LOG_INVALID_LOGGER_INSTANCEloggerInstance 仅接受日志记录器实例,而不接受配置对象。要传递配置对象,请使用 'logger'#5020
FST_ERR_LOG_INVALID_LOGGER_CONFIG日志记录器选项仅接受配置对象,而不接受日志记录器实例。要传递实例,请使用 'loggerInstance'#5020
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED您不能同时提供 'logger''loggerInstance'请仅提供一个选项。#5020
FST_ERR_REP_INVALID_PAYLOAD_TYPE回复有效负载可以是 stringBuffer使用 stringBuffer 作为有效负载。#1168
FST_ERR_REP_RESPONSE_BODY_CONSUMED使用 Response 作为回复有效负载,但主体正在被消耗。确保您没有消耗 Response.body#5286
FST_ERR_REP_ALREADY_SENT已经发送了响应。-#1336
FST_ERR_REP_SENT_VALUEreply.sent 的唯一可能值为 true-#1336
FST_ERR_SEND_INSIDE_ONERR您不能在 onError 钩子中使用 send-#1348
FST_ERR_SEND_UNDEFINED_ERR发生了未定义的错误。-#2074
FST_ERR_BAD_STATUS_CODE状态代码无效。使用有效的状态代码。#2082
FST_ERR_BAD_TRAILER_NAME使用无效的标头名称调用了 reply.trailer使用有效的标头名称。#3794
FST_ERR_BAD_TRAILER_VALUE使用无效的类型调用了 reply.trailer。预期为函数。使用函数。#3794
FST_ERR_FAILED_ERROR_SERIALIZATION序列化错误失败。-#4601
FST_ERR_MISSING_SERIALIZATION_FN缺少序列化函数。添加序列化函数。#3970
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN缺少 Content-Type 序列化函数。添加序列化函数。#4264
FST_ERR_REQ_INVALID_VALIDATION_INVOCATION无效的验证调用。缺少 HTTP 部分的验证函数或未提供模式。添加验证函数。#3970
FST_ERR_SCH_MISSING_ID提供的模式没有 $id 属性。添加 $id 属性。#1168
FST_ERR_SCH_ALREADY_PRESENT已经存在具有相同 $id 的模式。使用不同的 $id#1168
FST_ERR_SCH_CONTENT_MISSING_SCHEMA缺少与相应内容类型对应的模式。添加模式。#4264
FST_ERR_SCH_DUPLICATE具有相同属性的模式已经存在!使用不同的属性。#1954
FST_ERR_SCH_VALIDATION_BUILD为路由提供的 JSON 模式无效。修复 JSON 模式。#2023
FST_ERR_SCH_SERIALIZATION_BUILD为路由响应序列化提供的 JSON 模式无效。修复 JSON 模式。#2023
FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX响应模式应嵌套在有效的状态代码 (2XX) 下。使用有效的状态代码。#4554
FST_ERR_HTTP2_INVALID_VERSION仅在 node >= 8.8.1 中可用 HTTP2。使用更高版本的 node。#1346
FST_ERR_INIT_OPTS_INVALID初始化选项无效。使用有效的初始化选项。#1471
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE由于您的 HTTP 服务器不支持 closeIdleConnections 方法,因此无法将 forceCloseConnections 设置为 idleforceCloseConnections 使用不同的值。#3925
FST_ERR_DUPLICATED_ROUTE此 HTTP 方法已为此 URL 注册了控制器。使用不同的 URL 或为其他 HTTP 方法注册控制器。#2954
FST_ERR_BAD_URL路由器收到无效的 URL。使用有效的 URL。#2106
FST_ERR_ASYNC_CONSTRAINT使用异步约束时,路由器收到错误。-#4323
FST_ERR_INVALID_URLURL 必须是字符串。使用字符串作为 URL。#3653
FST_ERR_ROUTE_OPTIONS_NOT_OBJ路由的选项必须是对象。使用对象作为路由选项。#4554
FST_ERR_ROUTE_DUPLICATED_HANDLER不允许重复的路由处理程序。使用不同的处理程序。#4554
FST_ERR_ROUTE_HANDLER_NOT_FN路由的处理程序必须是函数。使用函数作为处理程序。#4554
FST_ERR_ROUTE_MISSING_HANDLER缺少路由的处理程序函数。添加处理程序函数。#4554
FST_ERR_ROUTE_METHOD_INVALID方法不是有效的值。使用有效的方法值。#4750
FST_ERR_ROUTE_METHOD_NOT_SUPPORTED不支持此路由的方法。使用受支持的方法。#4554
FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED不支持主体验证模式路由。使用不同的方法来处理路由。#4554
FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INTbodyLimit 选项必须是整数。使用整数作为 bodyLimit 选项。#4554
FST_ERR_ROUTE_REWRITE_NOT_STRrewriteUrl 必须为 string 类型。使用字符串作为 rewriteUrl#4554
FST_ERR_REOPENED_CLOSE_SERVERFastify 已经关闭,无法重新打开。-#2415
FST_ERR_REOPENED_SERVERFastify 已经在监听。-#2415
FST_ERR_PLUGIN_VERSION_MISMATCH已安装的 Fastify 插件与预期版本不匹配。使用兼容版本的插件。#2549
FST_ERR_PLUGIN_CALLBACK_NOT_FN钩子的回调不是函数。使用函数作为回调。#3106
FST_ERR_PLUGIN_NOT_VALID插件必须是函数或 Promise。使用函数或 Promise 作为插件。#3106
FST_ERR_ROOT_PLG_BOOTED根插件已经启动。-#3106
FST_ERR_PARENT_PLUGIN_BOOTED无法加载插件,因为父插件(直接从 avvio 映射)-#3106
FST_ERR_PLUGIN_TIMEOUT插件未及时启动。增加插件的超时时间。#3106
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE实例中不存在此装饰器。-#4554
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER正在注册的插件混合了异步和回调风格。-#5141
FST_ERR_VALIDATION请求未通过有效负载验证。检查请求有效负载。#4824
FST_ERR_LISTEN_OPTIONS_INVALID监听选项无效。检查监听选项。#4886
FST_ERR_ERROR_HANDLER_NOT_FN错误处理程序必须是函数setErrorHandler 提供函数。#5317