Skip to main content

错误

错误

¥Errors

目录

¥Table of contents

Node.js 中的错误处理

¥Error Handling In Node.js

未捕获的错误

¥Uncaught Errors

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

¥In Node.js, uncaught errors are likely to cause memory leaks, file descriptor leaks, and other major production issues. Domains were a failed attempt to fix this.

鉴于不可能合理地处理所有未捕获的错误,处理它们的最佳方法是 crash

¥Given that it is not possible to process all uncaught errors sensibly, the best way to deal with them is to crash.

捕获 Promise 中的错误

¥Catching Errors In Promises

如果你正在使用 promise,则应同步附加 .catch() 处理程序。

¥If you are using promises, you should attach a .catch() handler synchronously.

Fastify 中的错误

¥Errors In Fastify

Fastify 遵循“全有或全无”的方法,旨在尽可能精简和优化。开发者有责任确保正确处理错误。

¥Fastify follows an all-or-nothing approach and aims to be lean and optimal as much as possible. The developer is responsible for making sure that the errors are handled properly.

输入数据错误

¥Errors In Input Data

大多数错误都是由于意外输入数据造成的,因此我们推荐 根据 JSON 模式验证你的输入数据

¥Most errors are a result of unexpected input data, so we recommend validating your input data against a JSON schema.

在 Fastify 中捕获未捕获的错误

¥Catching Uncaught Errors In Fastify

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

¥Fastify tries to catch as many uncaught errors as it can without hindering performance. This includes:

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

    ¥synchronous routes, e.g. app.get('/', () => { throw new Error('kaboom') })

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

    ¥async routes, e.g. app.get('/', async () => { throw new Error('kaboom') })

两种情况下的错误都将被安全捕获并路由到 Fastify 的默认错误处理程序以获得通用 500 Internal Server Error 响应。

¥The error in both cases will be caught safely and routed to Fastify's default error handler for a generic 500 Internal Server Error response.

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

¥To customize this behavior you should use setErrorHandler.

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

¥Errors In Fastify Lifecycle Hooks And A Custom Error Handler

钩子文档

¥From the Hooks documentation:

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

¥If you get an error during the execution of your hook, just pass it to done() and Fastify will automatically close the request and send the appropriate error code to the user.

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

¥When a custom error handler has been defined through setErrorHandler, the custom error handler will receive the error passed to the done() callback (or through other supported automatic error handling mechanisms). If setErrorHandler has been used multiple times to define multiple handlers, the error will be routed to the most precedent handler defined within the error encapsulation context. Error handlers are fully encapsulated, so a setErrorHandler call within a plugin will limit the error handler to that plugin's context.

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

¥The root error handler is Fastify's generic error handler. This error handler will use the headers and status code in the Error object, if they exist. The headers and status code will not be automatically set if a custom error handler is provided.

在自定义错误处理程序中需要考虑的一些事项:

¥Some things to consider in your custom error handler:

  • 你可以使用 reply.send(data),其行为将与在 常规路由处理程序 中一样

    ¥you can reply.send(data), which will behave as it would in regular route handlers

    • 对象被序列化,触发 preSerialization 生命周期钩子(如果你定义了一个)

      ¥objects are serialized, triggering the preSerialization lifecycle hook if you have one defined

    • 字符串、缓冲区和流被发送到客户端,并带有适当的标头(无序列化)

      ¥strings, buffers, and streams are sent to the client, with appropriate headers (no serialization)

  • 你可以在自定义错误处理程序中抛出新错误 - 错误(新错误或重新抛出收到的错误参数) - 将调用父 errorHandler

    ¥You can throw a new error in your custom error handler - errors (new error or the received error parameter re-thrown) - will call the parent errorHandler.

    • onError 钩子只会在第一次抛出错误时触发一次。

      ¥onError hook will be triggered once only for the first error being thrown.

    • 生命周期钩子不会两次触发错误 - Fastify 内部监控错误调用,以避免在生命周期的回复阶段抛出错误而导致无限循环。(路由处理程序之后的那些)

      ¥an error will not be triggered twice from a lifecycle hook - Fastify internally monitors the error invocation to avoid infinite loops for errors thrown in the reply phases of the lifecycle. (those after the route handler)

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

¥When utilizing Fastify's custom error handling through setErrorHandler, you should be aware of how errors are propagated between custom and default error handlers.

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

¥If a plugin's error handler re-throws an error, and the error is not an instance of Error (as seen in the /bad route in the following example), it will not propagate to the parent context error handler. Instead, it will be caught by the default error handler.

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

¥To ensure consistent error handling, it is recommended to throw instances of Error. For instance, in the following example, replacing throw 'foo' with throw new Error('foo') in the /bad route ensures that errors propagate through the custom error handling chain as intended. This practice helps avoid potential pitfalls when working with custom error handling in Fastify.

例如:

¥For example:

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 错误代码

¥Fastify Error Codes

你可以访问 errorCodes 进行映射:

¥You can access errorCodes for mapping:

// ESM
import { errorCodes } from 'fastify'

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

例如:

¥For example:

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 使用的所有错误代码。

¥Below is a table with all the error codes that Fastify uses.

代码描述怎么解决讨论
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_FN错误指定了 SchemaErrorFormatter 选项。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当 content-type 设置为 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_CONFIGlogger 选项仅接受配置对象,而不是 logger 实例。要传递实例,请改用 '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_VERSIONHTTP2 仅在节点 >= 8.8.1 中可用。使用更高版本的节点。#1346
FST_ERR_INIT_OPTS_INVALID无效的初始化选项。使用有效的初始化选项。#1471
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE无法将 forceCloseConnections 设置为 idle,因为你的 HTTP 服务器不支持 closeIdleConnections 方法。forceCloseConnections 使用不同的值。#3925
FST_ERR_DUPLICATED_ROUTEHTTP 方法已具有该 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_BOOTEDRoot 插件已经启动。*#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