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

錯誤

錯誤

目錄

Node.js 中的錯誤處理

未捕獲的錯誤

在 Node.js 中,未捕獲的錯誤很可能會導致記憶體洩漏、檔案描述符洩漏和其他重大的生產問題。域 (Domains) 是修正這個問題的失敗嘗試。

鑑於無法合理地處理所有未捕獲的錯誤,處理它們的最佳方法是崩潰

在 Promise 中捕獲錯誤

如果您正在使用 promise,您應該同步附加一個 .catch() 處理器。

Fastify 中的錯誤

Fastify 遵循全有或全無的方法,並盡可能地保持精簡和最佳化。開發人員有責任確保正確處理錯誤。

輸入資料中的錯誤

大多數錯誤都是由於意外的輸入資料造成的,因此我們建議根據 JSON schema 驗證您的輸入資料

在 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 介面或具有 hook 的空裝飾器定義裝飾器。#5462
FST_ERR_HOOK_INVALID_TYPEhook 名稱必須是字串。請使用字串作為 hook 名稱。#1168
FST_ERR_HOOK_INVALID_HANDLERhook 回呼必須是一個函式。請使用函式作為 hook 回呼。#1168
FST_ERR_HOOK_INVALID_ASYNC_HANDLER非同步函式的參數過多。非同步 hook 不應使用 done 參數。請從非同步 hook 中移除 done 參數。#4367
FST_ERR_HOOK_NOT_SUPPORTED不支援該 hook。請使用支援的 hook。#4554
FST_ERR_MISSING_MIDDLEWARE您必須註冊一個用於處理中介軟體的外掛程式,請造訪 Middleware 取得更多資訊。請註冊一個用於處理中介軟體的外掛程式。#2014
FST_ERR_HOOK_TIMEOUThook 的回呼逾時。請增加 hook 的逾時時間。#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 hook 內使用 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 部分的驗證函式,也沒有提供 schema。請新增驗證函式。#3970
FST_ERR_SCH_MISSING_ID提供的 schema 沒有 $id 屬性。請新增 $id 屬性。#1168
FST_ERR_SCH_ALREADY_PRESENT已存在具有相同 $id 的 schema。請使用不同的 $id#1168
FST_ERR_SCH_CONTENT_MISSING_SCHEMA缺少對應內容類型的 schema。請新增 schema。#4264
FST_ERR_SCH_DUPLICATE已存在具有相同屬性的 schema!請使用不同的屬性。#1954
FST_ERR_SCH_VALIDATION_BUILD為路由提供的 JSON schema 無效。請修正 JSON schema。#2023
FST_ERR_SCH_SERIALIZATION_BUILD為路由回應序列化提供的 JSON schema 無效。請修正 JSON schema。#2023
FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX回應 schema 應巢狀在有效的狀態碼 (2XX) 下。請使用有效的狀態碼。#4554
FST_ERR_HTTP2_INVALID_VERSIONHTTP2 僅在 node >= 8.8.1 版本中可用。請使用較高版本的 node。#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不支援主體驗證 schema 路由。請為路由使用不同的方法。#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_FNhook 的回呼不是一個函式。請使用函式作為回呼。#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