Skip to Content

错误

目录

Node.js中的错误处理

未捕获的错误

在Node.js中,未捕获的错误可能导致内存泄漏、文件描述符泄漏以及其他重大生产问题。 Domains  是一种尝试解决此问题但失败的方法。

鉴于无法合理处理所有未捕获的错误,最好的方法是 崩溃 

在Promise中捕获错误

使用Promise时,请同步附加一个.catch()处理器。

Fastify中的错误

Fastify采取全有或全无的方法,并力求精简和优化。开发人员负责确保正确处理所有错误。

输入数据中的错误

大多数错误源于意外的输入数据,因此建议对输入数据进行JSON模式验证

在Fastify中捕获未捕获的错误

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

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

在这两种情况下,错误将被安全捕获并传递给Fastify的默认错误处理器,导致返回一个通用的500 Internal Server Error响应。

要自定义此行为,请使用 setErrorHandler

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

Hooks 文档

如果在执行您的钩子时遇到错误,请将其传递给 done(),Fastify 将自动关闭请求并向用户发送适当的错误代码。

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

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

使用自定义错误处理程序时应考虑以下事项:

  • reply.send(data) 行为与 常规路由处理器 相同

    • 对象会被序列化,触发 preSerialization 生命周期钩子(如果已定义)
    • 字符串、缓冲区和流会以适当的头信息发送给客户端(不进行序列化)
  • 在自定义错误处理程序中抛出新的错误将调用父级的 errorHandler

    • 对于首次抛出的错误,onError 钩子会被触发一次
    • 生命周期钩子阶段不会两次触发同一个错误。Fastify 内部监控错误调用来避免在回复阶段(路由处理器之后)抛出错误时出现无限循环

当使用Fastify的自定义错误处理功能时,通过setErrorHandler,请注意自定义和默认错误处理器之间如何传播错误。

如果插件中的错误处理器重新抛出一个不是Error 实例的错误,则该错误不会传递到父上下文的错误处理器。相反,它将被捕获并由默认错误处理器处理。这可以在下面示例中的/bad路由中看到。

为了确保一致的错误处理,请抛出Error类型的实例。例如,在/bad路由中,用throw new Error('foo')替换throw 'foo'以确保错误能够按照预期通过自定义错误处理链传播。这种做法有助于避免在使用Fastify时进行自定义错误处理时可能出现的问题。

例如:

const Fastify = require('fastify') // 初始化框架 const fastify = Fastify({ logger: true }) // 注册父级错误处理器 fastify.setErrorHandler((error, request, reply) => { reply.status(500).send({ ok: false }) }) fastify.register((app, options, next) => { // 注册子级错误处理器 fastify.setErrorHandler((error, request, reply) => { throw error }) fastify.get('/bad', async () => { // 抛出一个非Error类型的错误,'foo' throw 'foo' }) fastify.get('/good', async () => { // 抛出一个Error实例,'bar' throw new Error('bar') }) next() }) // 启动服务器 fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // 服务器正在${address}监听 })

Fastify 错误代码

您可以访问 errorCodes 进行映射:

// ESM import { errorCodes } from 'fastify' // CommonJS const errorCodes = require('fastify').errorCodes

例如:

const Fastify = require('fastify') // 实例化框架 const fastify = Fastify({ logger: true }) // 声明一个路由 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) { // 记录错误 this.log.error(error) // 发送错误响应 reply.status(500).send({ ok: false }) } else { // Fastify 将使用父级错误处理程序来处理此错误 reply.send(error) } }) // 启动服务器! fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // 服务器现在正在 ${address} 监听 })

以下是Fastify 使用的所有错误代码的表格。

代码描述解决方法讨论
FST_ERR_NOT_FOUND404 Not Found-#1168 
FST_ERR_OPTIONS_NOT_OBJFastify选项指定错误。快速启动选项应该是一个对象。#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_DEC_UNDECLARED尝试访问尚未声明的装饰器。在使用之前声明该装饰器。# 
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_READABLE_STREAM_LOCKED使用 ReadableStream 作为回复有效负载,但已被其他读者锁定。确保在发送之前不要调用 Readable.getReader() 或使用 reader.releaseLock() 在发送前释放锁。#5920 
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_INIT_OPTS_INVALID初始化选项无效。使用有效的初始化选项。#1471 
FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE将 forceCloseConnections 设置为 idle 不可用,因为您的 HTTP 服务器不支持 closeIdleConnections 方法。使用不同的值设置 forceCloseConnections#3925 
DUPLICATE_ROUTE对于该 URL,HTTP 方法已注册了控制器。使用不同的 URL 或为另一个 HTTP 方法注册控制器。#2954 
INVALID_URL路由器收到一个无效的 URL。使用有效的 URL。#2106 
ASYNC_CONSTRAINT_ERROR在使用异步约束时,路由器收到了错误。-#4323 
INVALID_URL_TYPEURL 必须是字符串类型。使用字符串类型的 URL。#3653 
ROUTE_OPTIONS_NOT_OBJECT路由的选项必须是一个对象。为路由选项使用一个对象。#4554 
DUPLICATE_HANDLER不允许为路由设置重复的处理程序。使用不同的处理程序。#4554 
ROUTE_HANDLER_NOT_FUNCTION路由的处理程序必须是一个函数。为处理程序使用一个函数。#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 
FST_ERR_ERROR_HANDLER_ALREADY_SET错误处理程序已在当前作用域中设置。 设置 allowErrorHandlerOverride: true 以允许覆盖。默认情况下,setErrorHandler 每个封装上下文只能调用一次。#6097