Skip to Content

工厂函数

Fastify 模块导出了一个工厂函数,用于创建新的 Fastify 服务器 实例。该工厂函数接受一个选项对象,用于自定义生成的实例。本文档描述了该选项对象中可用的属性。

http

  • 默认值: null

一个用于配置服务器监听套接字的对象。选项与 Node.js 核心的 createServer 方法相同。

如果设置了选项 http2 或者 https,则忽略此选项。

http2

  • 默认值: false

如果为 true,将使用 Node.js 核心的 HTTP/2  模块来绑定套接字。

https

  • 默认值: null

一个用于配置服务器 TLS 监听套接字的对象。选项与 Node.js 核心的 createServer 方法相同。 当此属性为 null 时,套接字将不会配置为 TLS。

如果设置了 http2 选项,则同样适用此选项。

connectionTimeout

  • 默认值: 0 (无超时)

定义服务器的超时时间(以毫秒为单位)。请参阅文档中的 server.timeout 属性 了解此选项的效果。

当指定了 serverFactory 选项时,将忽略此选项。

keepAliveTimeout

  • 默认值: 72000 (72 秒)

定义服务器的保持连接超时时间(以毫秒为单位)。请参阅文档中的 server.keepAliveTimeout 属性 了解此选项的效果。此选项仅在使用 HTTP/1 时适用。

当指定了 serverFactory 选项时,将忽略此选项。

forceCloseConnections

  • 默认值:如果 HTTP 服务器允许,则为 "idle",否则为 false

当设置为 true 时,在调用 close 方法后,服务器将遍历当前的持久连接,并销毁它们的套接字 

⚠ 警告: 连接不会被检查以确定请求是否已完成。

Fastify 优先使用 HTTP 服务器提供的 closeAllConnections 方法(如果支持的话),否则将使用内部连接跟踪机制。

当设置为 "idle" 时,在调用 close 方法后,服务器将遍历当前没有发送请求或等待响应的持久连接,并销毁它们的套接字。此值仅在 HTTP 服务器支持 closeIdleConnections 方法时有效,否则尝试设置它会抛出异常。

maxRequestsPerSocket

  • 默认值:0(无限制)

定义一个套接字在关闭保持连接之前可以处理的最大请求数量。参见 server.maxRequestsPerSocket 属性以了解此选项的效果。此选项仅适用于 HTTP/1.1 协议,并且当指定了 serverFactory 选项时,将被忽略。

ℹ️ 注意: 在撰写本文时,只有 node >= v16.10.0 支持此选项。

requestTimeout

  • 默认值:0(无限制)

定义了从客户端接收整个请求的最大毫秒数。参见server.requestTimeout 属性 以了解此选项的效果。

当指定了 serverFactory 选项时,此选项将被忽略。 必须将其设置为非零值(例如120秒),以防服务器在没有反向代理的情况下部署时受到潜在的拒绝服务攻击。

ℹ️ 注意: 在撰写本文时,仅支持 node >= v14.11.0 的版本

ignoreTrailingSlash

  • 默认值:false

Fastify 使用 find-my-way  处理路由。默认情况下,Fastify 会考虑尾部斜杠。 路径如 /foo/foo/ 被视为不同的路径。如果您希望更改此行为,请将该标志设置为 true。这样,无论 /foo 还是 /foo/ 都指向相同的路由。此选项适用于所有路由注册的服务器实例。

const fastify = require('fastify')({ ignoreTrailingSlash: true }) // 注册 "/foo" 和 "/foo/" fastify.get('/foo/', function (req, reply) { reply.send('foo') }) // 注册 "/bar" 和 "/bar/" fastify.get('/bar', function (req, reply) { reply.send('bar') })

ignoreDuplicateSlashes

  • 默认值:false

Fastify 使用 find-my-way  处理路由。你可以使用 ignoreDuplicateSlashes 选项从路径中移除重复的斜杠。它会移除路由路径和请求 URL 中的重复斜杠。此选项适用于服务器实例的所有路由注册。

ignoreTrailingSlashignoreDuplicateSlashes 都设置为 true 时,Fastify 将先移除重复的斜杠,然后是尾部斜杠,例如 //a//b//c// 将被转换为 /a/b/c

const fastify = require('fastify')({ ignoreDuplicateSlashes: true }) // 注册 "/foo/bar/" fastify.get('///foo//bar//', function (req, reply) { reply.send('foo') })

maxParamLength

  • 默认值:100

你可以通过使用 maxParamLength 选项为参数化(标准、正则表达式和多参数)路由设置自定义的参数长度,默认值是 100 字符。如果达到最大长度限制,将调用未找到的路由。

这在你有基于正则表达式的路由时特别有用,可以保护你免受 ReDoS 攻击 

bodyLimit

  • 默认值:1048576 (1MiB)

定义服务器允许接受的最大有效负载大小(以字节为单位)。默认的 body reader 在 body 大小超过此限制时发送 FST_ERR_CTP_BODY_TOO_LARGE 回复。 如果提供了 preParsing 钩子,则此限制应用于钩子返回的流大小(即“解码”后的 body 大小)。

onProtoPoisoning

  • 默认值: 'error'

定义了框架在解析包含 __proto__ 的 JSON 对象时必须采取的操作。此功能由 secure-json-parse  提供。有关原型中毒攻击的更多详细信息,请参阅Prototype Poisoning

可能值为 'error''remove''ignore'

onConstructorPoisoning

  • 默认值: 'error'

定义了框架在解析包含 constructor 的 JSON 对象时必须采取的操作。此功能由 secure-json-parse  提供。有关原型中毒攻击的更多详细信息,请参阅Prototype Poisoning

可能值为 'error''remove''ignore'

logger

Fastify 包含了通过 Pino  日志器实现的内置日志记录功能。此属性用于配置内部的日志实例。

该属性可能具有的值包括:

  • 默认:false。禁用日志记录。所有日志方法将指向一个空的日志器 abstract-logging  实例。

  • object: 一个标准的 Pino 选项对象 。此对象将直接传递给 Pino 构造函数。如果以下属性不存在于该对象中,则会相应地添加这些属性:

    • level: 最低日志级别。如果没有设置,默认为 'info'
    • serializers: 一个序列化函数的哈希表。默认情况下,为 req(传入请求对象)、res(传出响应对象)和 err(标准 Error 对象)添加了序列化器。当日志方法接收到具有这些属性的对象时,则会使用相应的序列化器来处理该属性。例如:
fastify.get('/foo', function (req, res) { req.log.info({req}) // 记录序列化的请求对象 res.send('foo') })

任何用户提供的序列化器将覆盖相应属性的默认序列化器。

loggerInstance

  • 默认值:null

一个自定义的 logger 实例。该 logger 必须是 Pino 的实例,或者符合 Pino 接口,具体方法包括:info, error, debug, fatal, warn, trace, child。例如:

const pino = require('pino')(); const customLogger = { info: function (o, ...n) {}, warn: function (o, ...n) {}, error: function (o, ...n) {}, fatal: function (o, ...n) {}, trace: function (o, ...n) {}, debug: function (o, ...n) {}, child: function() { const child = Object.create(this); child.pino = pino.child(...arguments); return child; }, }; const fastify = require('fastify')({logger: customLogger});

disableRequestLogging

  • 默认值:false

当启用日志记录时,Fastify会在收到请求和发送响应时发出一个“info”级别的日志消息。通过将此选项设置为true,可以禁用这些日志消息。这允许通过附加自定义的onRequestonResponse钩子来实现更灵活的请求开始和结束的日志记录。

其他将被禁用的日志条目包括:

  • 默认onResponse钩子在回复回调错误时写入的错误日志
  • defaultErrorHandler在处理错误管理时写入的错误和信息日志
  • 当请求不存在的路由时,由fourOhFour处理器写入的信息日志

Fastify发出的其他日志消息将保持启用状态,例如当服务器关闭时收到请求而发出的弃用警告和其他消息。

// 用于复制禁用功能的钩子示例。 fastify.addHook('onRequest', (req, reply, done) => { req.log.info({ url: req.raw.url, id: req.id }, '收到请求') done() }) fastify.addHook('onResponse', (req, reply, done) => { req.log.info({ url: req.raw.originalUrl, statusCode: reply.raw.statusCode }, '请求完成') done() })

serverFactory

你可以通过使用serverFactory选项将自定义的HTTP服务器传递给Fastify。

serverFactory是一个函数,它接受一个handler参数(该参数接收requestresponse对象作为参数)以及一个选项对象,这个选项对象是你传递给Fastify的那个对象。

const serverFactory = (handler, opts) => { const server = http.createServer((req, res) => { handler(req, res) }) return server } const fastify = Fastify({ serverFactory }) fastify.get('/', (req, reply) => { reply.send({ hello: 'world' }) }) fastify.listen({ port: 3000 })

内部,Fastify使用Node核心HTTP服务器的API,因此如果你使用的是自定义服务器,则必须确保暴露相同的API。如果不一致,你可以在serverFactory函数中的返回语句之前增强服务器实例。

caseSensitive

  • 默认值:true

当设置为true时,路由注册为大小写敏感的。也就是说,/foo不等于/Foo。 当设置为false时,则路由是大小写不敏感的。

请注意,将此选项设置为falseRFC3986 相违背。

通过将caseSensitive设置为false,所有路径都将匹配为小写形式,但路由参数或通配符将保留其原始字母大小写。 此选项不会影响查询字符串,请参阅querystringParser以更改它们的处理方式。

fastify.get('/user/:username', (request, reply) => { // 给定URL:/USER/NodeJS console.log(request.params.username) // -> 'NodeJS' })

允许不安全正则表达式

  • 默认值:false

默认情况下禁用,因此路由仅允许安全的正则表达式。要使用不安全的表达式,请将 allowUnsafeRegex 设置为 true

fastify.get('/user/:id(^([0-9]+){4}$)', (request, reply) => { // 如果没有设置 allowUnsafeRegex = true,则会抛出错误 })

请求ID头

  • 默认值:'request-id'

用于设置请求标识符的头部名称。请参阅 请求ID 部分。 将 requestIdHeader 设置为 true 将使 requestIdHeader"request-id"。 将 requestIdHeader 设置为非空字符串将使用指定的字符串作为 requestIdHeader。 默认情况下,requestIdHeader 被设置为 false 并立即使用 genReqId。 将 requestIdHeader 设置为空字符串 ("") 将使 requestIdHeaderfalse

const fastify = require('fastify')({ requestIdHeader: 'x-custom-id', // -> 如果存在,则使用 'X-Custom-Id' 头部 //requestIdHeader: false, // -> 始终使用 genReqId })

请求ID日志标签

  • 默认值:'reqId'

定义在记录请求时使用的请求标识符的标签。

requestIdLogLabel

  • 默认值:'reqId'

定义在记录请求时使用的请求标识符标签。

genReqId

  • 默认值:如果提供,则为'request-id'头的值,否则为单调递增整数

用于生成请求ID的函数。它将接收原始传入请求作为参数。此函数应无错误。

特别是在分布式系统中,您可能希望覆盖默认的ID生成行为,如下所示。如果您想生成UUID,可以查看 hyperid 

ℹ️ 注意: 如果设置了 requestIdHeader 头(默认为’request-id’),则不会调用 genReqId 函数。

let i = 0 const fastify = require('fastify')({ genReqId: function (req) { return i++ } })

trustProxy

  • 默认值:false
  • true/false: 信任所有代理 (true) 或不信任任何代理 (false)。
  • string: 只信任给定的IP/CIDR(例如 '127.0.0.1')。可以是逗号分隔的多个值列表(例如 '127.0.0.1,192.168.1.1/24')。
  • Array<string>: 只信任给定的IP/CIDR列表(例如 ['127.0.0.1'])。
  • number: 从面向前端的代理服务器开始,信任第n跳作为客户端。
  • Function: 自定义信任函数,接受 address 作为第一个参数
    function myTrustFn(address, hop) { return address === '1.2.3.4' || hop === 1 }

通过启用 trustProxy 选项,Fastify 将知道它位于代理之后,并且可以信任 X-Forwarded-* 头部字段,否则这些头部字段很容易被伪造。

const fastify = Fastify({ trustProxy: true })

更多示例,请参阅 @fastify/proxy-addr 包。

您可以在 request 对象上访问 ip, ips, hostprotocol 值。

fastify.get('/', (request, reply) => { console.log(request.ip) console.log(request.ips) console.log(request.host) console.log(request.protocol) })

ℹ️ 注意: 如果请求包含多个 x-forwarded-hostx-forwarded-proto 头部,则仅使用最后一个头部来推导 request.hostnamerequest.protocol

pluginTimeout

  • 默认值:10000

插件加载的最大时间(以 毫秒 为单位)。如果超过该时间,ready 将完成并抛出一个带有代码 'ERR_AVVIO_PLUGIN_TIMEOUT'Error。设置为 0 可禁用此检查。这控制了 avvio timeout 参数。

querystringParser

Fastify 使用的默认查询字符串解析器是 Node.js 核心模块 querystring 的一个性能更高的分支,名为 fast-querystring

您可以使用此选项来使用自定义解析器,例如 qs

如果您只想让键(而不是值)不区分大小写,我们建议使用自定义解析器将仅将键转换为小写:

const qs = require('qs') const fastify = require('fastify')({ querystringParser: str => qs.parse(str) })

您还可以使用 Fastify 的默认解析器但更改一些处理行为,例如下面的示例中不区分大小写的键和值:

const querystring = require('fast-querystring') const fastify = require('fastify')({ querystringParser: str => querystring.parse(str.toLowerCase()) })

exposeHeadRoutes

  • 默认值:true

自动为每个定义的 GET 路由创建一个同级的 HEAD 路由。如果您希望使用自定义 HEAD 处理程序而不禁用此选项,请确保在定义 GET 路由之前定义它。

约束

Fastify 内置的路由约束由 find-my-way 提供,允许通过 versionhost 对路由进行限制。你可以通过提供一个包含 find-my-way 策略的 constraints 对象来添加新的约束策略或覆盖内置策略。有关约束策略的更多信息,请参阅 find-my-way  文档。

const customVersionStrategy = { storage: function () { const versions = {} return { get: (version) => { return versions[version] || null }, set: (version, store) => { versions[version] = store } } }, deriveVersion: (req, ctx) => { return req.headers['accept'] } } const fastify = require('fastify')({ constraints: { version: customVersionStrategy } })

return503OnClosing

  • 默认值:true

在调用 close 服务器方法后返回 503。如果设置为 false,则服务器会像平常一样处理传入的请求。

ajv

配置 Fastify 使用的 Ajv v8 实例(无需提供自定义实例)。默认配置在 #schema-validator 部分进行了说明。

const fastify = require('fastify')({ ajv: { customOptions: { removeAdditional: 'all' // 参见 [ajv options](https://ajv.js.org/options.html#removeadditional) }, plugins: [ require('ajv-merge-patch'), [require('ajv-keywords'), 'instanceof'] // 使用方法:[插件, 插件选项] - 带有选项的插件 // 使用方法:插件 - 不带选项的插件 ] } })

serializerOpts

自定义默认的 fast-json-stringify 实例选项,该实例用于序列化响应负载:

const fastify = require('fastify')({ serializerOpts: { rounding: 'ceil' } })

http2SessionTimeout

  • 默认值:72000

设置每个传入的 HTTP/2 会话的默认 超时时间  (以毫秒为单位)。在超时时,会话将被关闭。

此选项用于提供优雅的“关闭”体验,特别是在使用 HTTP/2 时。选择较低默认值是为了减轻拒绝服务攻击的影响。当服务器位于负载均衡器之后或可以自动扩展时,可以根据实际需求增加该值。Node 核心默认设置为 0

frameworkErrors

  • 默认值:null

Fastify 为最常见的用例提供了默认错误处理程序。可以通过此选项使用自定义代码覆盖一个或多个这些处理程序。

ℹ️ 注意: 当前仅实现了 FST_ERR_BAD_URLFST_ERR_ASYNC_CONSTRAINT 错误类型。

const fastify = require('fastify')({ frameworkErrors: function (error, req, res) { if (error instanceof FST_ERR_BAD_URL) { res.code(400) return res.send("提供的 URL 不有效") } else if(error instanceof FST_ERR_ASYNC_CONSTRAINT) { res.code(400) return res.send("提供的头信息不有效") } else { res.send(err) } } })

clientErrorHandler

设置一个监听由客户端连接发出的error事件并响应400状态码的客户端错误处理器 

可以通过此选项覆盖默认的clientErrorHandler

  • 默认值:
function defaultClientErrorHandler (err, socket) { if (err.code === 'ECONNRESET') { return } const body = JSON.stringify({ error: http.STATUS_CODES['400'], message: 'Client Error', statusCode: 400 }) this.log.trace({ err }, '客户端错误') if (socket.writable) { socket.end([ 'HTTP/1.1 400 Bad Request', `Content-Length: ${body.length}`, `Content-Type: application/json\r\n\r\n${body}` ].join('\r\n')) } }

ℹ️ 注意: clientErrorHandler 使用原始套接字。处理器需要返回一个包含状态行、HTTP头和消息体的正确格式化的 HTTP 响应。在尝试写入套接字之前,处理器应该检查套接字是否仍然可写,因为套接字可能已经被销毁。

const fastify = require('fastify')({ clientErrorHandler: function (err, socket) { const body = JSON.stringify({ error: { message: '客户端错误', code: '400' } }) // `this` 绑定到 fastify 实例 this.log.trace({ err }, '客户端错误') // 处理器负责生成有效的 HTTP 响应 socket.end([ 'HTTP/1.1 400 Bad Request', `Content-Length: ${body.length}`, `Content-Type: application/json\r\n\r\n${body}` ].join('\r\n')) } })

rewriteUrl

设置一个同步回调函数,该函数必须返回一个字符串以允许重写URL。当您位于更改URL的代理后面时这非常有用。 重写URL将修改req对象的url属性。

请注意,rewriteUrl在路由之前被调用,并且它不是封装配置而是全局实例配置。

// @param {object} req 原始Node.js HTTP请求对象(非FastifyRequest对象)。 // @this Fastify 根Fastify实例(非封装实例)。 // @returns {string} 请求应映射到的路径。 function rewriteUrl (req) { if (req.url === '/hi') { this.log.debug({ originalUrl: req.url, url: '/hello' }, '重写URL'); return '/hello' } else { return req.url; } }

useSemicolonDelimiter

  • 默认值:false

Fastify 使用 find-my-way ,该库支持使用分号(代码59)字符将路径和查询字符串分开,例如 /dev;foo=bar。此决定源自于[delvedor/find-my-way#76] (https://github.com/delvedor/find-my-way/issues/76)。因此,此选项将支持在分号上进行分割的向后兼容性需求。要启用在分号上进行分割的支持,请将  useSemicolonDelimiter 设置为 true

const fastify = require('fastify')({ useSemicolonDelimiter: true }) fastify.get('/dev', async (request, reply) => { // 例如请求 `/dev;foo=bar` // 将产生以下查询参数结果 `{ foo = 'bar' }` return request.query })

允许错误处理程序覆盖

  • 默认值: true

警告: 在下一个主要版本中,此选项将默认设置为 false

当设置为 false 时,它会防止在相同的范围内多次调用 setErrorHandler,确保之前的错误处理程序不会被意外覆盖。

错误使用示例:

app.setErrorHandler(function freeSomeResources () { // 永远不执行,内存泄漏 }) app.setErrorHandler(function anotherErrorHandler () { // 覆盖前面的处理程序 })

实例

服务器方法

server

fastify.server: 返回自 Fastify 工厂函数 的 Node 核心 server  对象。

⚠ 警告: 如果使用不当,某些 Fastify 功能可能会受到影响。 建议仅用于附加监听器。

after

当前插件及其内部注册的所有插件加载完成后被调用。它始终在 fastify.ready 方法之前执行。

fastify .register((instance, opts, done) => { console.log('当前插件') done() }) .after(err => { console.log('当前插件之后') }) .register((instance, opts, done) => { console.log('下一个插件') done() }) .ready(err => { console.log('所有内容已加载') })

如果 after() 被调用时不带函数,则返回一个 Promise

fastify.register(async (instance, opts) => { console.log('当前插件') }) await fastify.after() console.log('当前插件之后') fastify.register(async (instance, opts) => { console.log('下一个插件') }) await fastify.ready() console.log('所有内容已加载')

ready

当所有插件都加载完毕后调用的函数。如果出现问题,它会接收一个错误参数。

fastify.ready(err => { if (err) throw err })

如果没有传入任何参数,则返回一个 Promise

fastify.ready().then(() => { console.log('启动成功!') }, (err) => { console.log('发生错误', err) })

监听

启动服务器并在内部等待 .ready() 事件。签名是 .listen([options][, callback])options 对象和 callback 参数扩展了 Node.js 核心  的选项对象。因此,所有核心选项都可用,并且还提供了以下特定于 Fastify 的附加选项:

listenTextResolver

设置一个可选解析器,用于在服务器成功启动后记录的日志文本。 可以通过此选项覆盖默认的Server listening at [address]日志条目。

server.listen({ port: 9080, listenTextResolver: (address) => { return `Prometheus metrics server is listening at ${address}` } })

默认情况下,服务器将在没有提供特定主机时由localhost解析的地址上监听。如果希望在所有可用接口上监听,则可以指定0.0.0.0作为地址以监听所有IPv4地址。上述提供的地址参数将返回第一个这样的IPv4地址。以下表格详细列出了针对localhost的目标主机可能值,以及这些主机值的结果。

主机IPv4IPv6
::*
:: + ipv6Only🚫
0.0.0.0🚫
localhost
127.0.0.1🚫
::1🚫

* 使用::作为地址时,将在所有IPv6地址上监听,并且根据操作系统可能还会在所有IPv4地址 上监听。

当决定在所有接口上监听时要小心;这会带来固有的安全风险 

默认情况下,服务器将在port: 0(选择第一个可用的端口)和host: 'localhost'上监听:

fastify.listen((err, address) => { if (err) { fastify.log.error(err) process.exit(1) } })

指定地址也是支持的:

fastify.listen({ port: 3000, host: '127.0.0.1' }, (err, address) => { if (err) { fastify.log.error(err) process.exit(1) } })

指定地址也是支持的:

fastify.listen({ port: 3000, host: '127.0.0.1' }, (err, address) => { if (err) { fastify.log.error(err) process.exit(1) } })

如果没有提供回调函数,则返回一个Promise:

fastify.listen({ port: 3000 }) .then((address) => console.log(`server listening on ${address}`)) .catch(err => { console.log('Error starting server:', err) process.exit(1) })

在部署到Docker容器(以及其他可能的容器)时,建议监听 0.0.0.0 ,因为它们默认不会将映射端口暴露给 localhost

fastify.listen({ port: 3000, host: '0.0.0.0' }, (err, address) => { if (err) { fastify.log.error(err) process.exit(1) } })

如果省略 port(或设置为零),则会自动选择一个可用的随机端口(可通过 fastify.server.address().port 获取)。

listen 的默认选项如下:

fastify.listen({ port: 0, host: 'localhost', exclusive: false, readableAll: false, writableAll: false, ipv6Only: false }, (err) => {})

地址

此方法返回服务器正在监听的一组地址数组。如果你在调用 listen() 之前或 close() 函数之后调用它,将返回一个空数组。

await fastify.listen({ port: 8080 }) const addresses = fastify.addresses() // [ // { port: 8080, family: 'IPv6', address: '::1' }, // { port: 8080, family: 'IPv4', address: '127.0.0.1' } // ]

请注意,数组中包含 fastify.server.address() 的结果。

路由

访问内部路由器的 lookup 方法并匹配请求到适当的处理程序的方法:

fastify.routing(req, res)

添加路由

向服务器添加路由的方法,它还具有简写函数,请参阅此处

检查路由是否存在

用于检查路由是否已注册到内部路由器的方法。此方法需要一个对象作为参数,urlmethod 是必需的字段。还可以指定 constraints 字段。如果路由已注册,则该方法返回 true,否则返回 false

const routeExists = fastify.hasRoute({ url: '/', method: 'GET', constraints: { version: '1.0.0' } // 可选 }) if (routeExists === false) { // 添加路由 }

查找路由

用于检索已注册到内部路由器的路由的方法。此方法需要一个对象作为参数,urlmethod 是必需的字段。还可以指定 constraints 字段。 如果找到该路由,则返回一个路由对象;否则返回 null

const route = fastify.findRoute({ url: '/artists/:artistId', method: 'GET', constraints: { version: '1.0.0' } // 可选 }) if (route !== null) { // 执行一些路由检查 console.log(route.params) // `{artistId: ':artistId'}` }

关闭

fastify.close(callback): 调用此函数来关闭服务器实例并运行'onClose'钩子。

调用 close 也会导致服务器对每个新的传入请求返回一个 503 错误,并销毁该请求。有关更改此行为的选项,请参阅return503OnClosing标志。

如果没有参数,则会返回一个 Promise:

fastify.close().then(() => { console.log('成功关闭!') }, (err) => { console.log('发生错误', err) })

装饰*

如果需要装饰 fastify 实例、Reply 或 Request,请参阅此处

注册

Fastify 允许用户通过插件扩展其功能。一个插件可以是一组路由,服务器装饰器或任何其他内容,请参阅此处

添加钩子

用于在 Fastify 生命周期中添加特定钩子的函数,请参阅此处

前缀

将被前缀到路由上的完整路径。

示例:

fastify.register(function (instance, opts, done) { instance.get('/foo', function (request, reply) { // 将记录 "前缀: /v1" request.log.info('前缀: %s', instance.prefix) reply.send({ prefix: instance.prefix }) }) instance.register(function (instance, opts, done) { instance.get('/bar', function (request, reply) { // 将记录 "前缀: /v1/v2" request.log.info('前缀: %s', instance.prefix) reply.send({ prefix: instance.prefix }) }) done() }, { prefix: '/v2' }) done() }, { prefix: '/v1' })

插件名称

当前插件的名称。根插件称为 'fastify'。定义名称的方法有以下几种(按顺序):

  1. 如果你使用 fastify-plugin ,则会使用元数据 name
  2. 如果导出的插件具有 Symbol.for('fastify.display-name') 属性,则该属性的值将被使用。 示例:pluginFn[Symbol.for('fastify.display-name')] = "自定义名称"
  3. 如果你通过 module.exports 导出一个插件,那么文件名会被使用。
  4. 如果你使用常规 函数声明 ,则会使用函数名称。

备用方案:你的插件的前两行将代表插件名称。换行符将被替换为 --,这有助于在处理多个插件时识别根本原因。

⚠ 警告: 如果你必须处理嵌套插件,则名称会因使用 fastify-plugin  的方式而不同,因为没有创建新的作用域,因此我们无法附加上下文数据。在这种情况下,插件名称将表示所有涉及插件的启动顺序,格式为 fastify -> 插件-A -> 插件-B

检查已注册插件

用于检查特定插件是否已被注册的方法。依赖于插件元数据名称。如果插件已注册,则返回 true,否则返回 false

const fastify = require('fastify')() fastify.register(require('@fastify/cookie'), { secret: 'my-secret', parseOptions: {} }) fastify.ready(() => { fastify.hasPlugin('@fastify/cookie') // true })

监听源

服务器当前正在监听的来源。 例如,基于TCP套接字的服务器会返回一个基础地址如 http://127.0.0.1:3000, 而Unix套接字服务器则会返回套接字路径,例如 fastify.temp.sock

日志

日志实例,请参阅 这里

版本号

Fastify 实例的版本号。用于插件支持。有关插件如何使用版本号的信息,请参见 插件

注入

伪造HTTP注入(测试目的) 此处有更多详情。

添加HTTP方法

Fastify 默认支持 GET, HEAD, TRACE, DELETE, OPTIONS, PATCH, PUTPOST HTTP 方法。 addHttpMethod 方法允许向服务器添加任何非标准的HTTP方法,这些方法由 Node.js 支持 (请参阅 Node.js 文档 )。

// 添加一个名为 'MKCOL' 的新 HTTP 方法,并支持请求体 fastify.addHttpMethod('MKCOL', { hasBody: true, }) // 添加一个不支持请求体的新 HTTP 方法,例如 'COPY' fastify.addHttpMethod('COPY')

调用 addHttpMethod 后,可以使用路由简写方法为新HTTP方法定义路由:

fastify.addHttpMethod('MKCOL', { hasBody: true }) fastify.mkcol('/', (req, reply) => { // 处理 'MKCOL' 请求 })

添加模式

fastify.addSchema(schemaObj) 方法将 JSON 模式添加到 Fastify 实例中。这允许你在应用程序的任何地方通过使用标准 $ref 关键字来重用它。

要了解更多信息,请阅读 验证和序列化 文档。

获取Schemas

fastify.getSchemas(),返回所有通过.addSchema添加的模式的哈希表。 哈希表中的键是提供的JSON Schema的$id

获取Schema

fastify.getSchema(id),返回与.addSchema中使用的匹配id的JSON模式。如果未找到,则返回undefined

设置回复序列化器

为所有路由设置回复序列化器。如果没有设置Reply.serializer(func),则将其用作默认值。处理程序是完全封装的,因此不同的插件可以设置不同的错误处理器。注意:函数参数仅在状态码为2xx时调用。查看setErrorHandler以了解错误处理。

fastify.setReplySerializer(function (payload, statusCode){ // 使用同步函数序列化负载 return `my serialized ${statusCode} content: ${payload}` })

设置验证编译器

为所有路由设置模式验证编译器。请参阅#schema-validator

设置模式错误格式化程序

为所有路由设置模式错误格式化程序。请参阅#error-handling

设置序列化解析器编译器

为所有路由设置模式序列化解析器编译器。请参阅#schema-serializer

ℹ️ 注意: 如果设置了setReplySerializer,则优先使用!

验证器编译器

此属性可用于获取模式验证器。如果未设置,则在服务器启动前为 null,然后变为一个具有以下签名的函数:function ({ schema, method, url, httpPart }),该函数返回输入 schema 编译后的用于验证数据的函数。输入 schema 可以访问所有通过 .addSchema 函数添加的共享模式。

序列化器编译器

此属性可用于获取模式序列化器。如果未设置,则在服务器启动前为 null,然后变为一个具有以下签名的函数:function ({ schema, method, url, httpPart }),该函数返回输入 schema 编译后的用于验证数据的函数。输入 schema 可以访问所有通过 .addSchema 函数添加的共享模式。

模式错误格式化器

此属性可用于设置一个函数,该函数在 validationCompiler 无法验证模式时用于格式化错误。请参阅 #error-handling

schemaController

此属性可用于完全管理:

  • bucket:您的应用程序的模式将存储在此位置。
  • compilersFactory:必须编译 JSON 模式的模块。

当您的模式存储在 Fastify 未知的数据结构中时,这会很有用。

另一个使用场景是调整所有模式处理。通过这种方式,可以使用 Ajv v8 JTD 或 Standalone 功能。要使用 JTD 或 Standalone 模式,请参阅 @fastify/ajv-compiler 文档

const fastify = Fastify({ schemaController: { /** * 当调用 `fastify.register()` 时,此工厂函数将被调用。 * 如果添加了一些模式,则可以接收父上下文的模式作为输入。 * @param {object} parentSchemas 这些模式将由返回的 `bucket` 的 `getSchemas()` 方法函数返回。 */ bucket: function factory (parentSchemas) { return { add (inputSchema) { // 此函数必须存储用户添加的模式。 // 当调用 `fastify.addSchema()` 时将调用此函数。 }, getSchema (schema$id) { // 此函数必须返回由 `schema$id` 请求的原始模式。 // 当调用 `fastify.getSchema(id)` 时将调用此函数。 return aSchema }, getSchemas () { // 此函数必须返回所有路由模式 `$ref` 引用的模式。 // 它必须返回一个 JSON,其中属性是模式 `$id`,值是原始 JSON 模式。 const allTheSchemaStored = { 'schema$id1': schema1, 'schema$id2': schema2 } return allTheSchemaStored } } }, /** * 编译器工厂允许您完全控制 Fastify 生命周期中的验证器和序列化器,为您的编译器提供封装。 */ compilersFactory: { /** * 每当需要新的验证器实例时都会调用此工厂。仅在 `fastify.register()` 被调用且封装上下文中添加了新模式的情况下才会被调用。 * 如果某些模式已被添加,则可以接收父上下文的模式作为输入参数。 * @param {object} externalSchemas 这些模式将由 `bucket.getSchemas()` 返回。需要这些模式来解析外部引用 $ref。 * @param {object} ajvServerOption 用于构建编译器的服务器端 `ajv` 选项 */ buildValidator: function factory (externalSchemas, ajvServerOption) { // 此工厂函数必须返回一个模式验证器编译器。详情请参阅 [模式验证器](./Validation-and-Serialization.md#schema-validator) const yourAjvInstance = new Ajv(ajvServerOption.customOptions) return function validatorCompiler ({ schema, method, url, httpPart }) { return yourAjvInstance.compile(schema) } }, /** * 当需要新的序列化器实例时调用此工厂函数。 * 只有在 `fastify.register()` 被调用且封装上下文中添加了新模式的情况下,才会被调用。 * 如果某些模式已被添加,则可以接收父上下文中的模式作为输入参数。 * @param {object} externalSchemas 这些模式将由 `bucket.getSchemas()` 返回。 用于解析外部引用 $ref。 * @param {object} serializerOptsServerOption 服务器的 `serializerOpts` 选项,根据这些选项构建编译器 */ buildSerializer: function 工厂函数 (externalSchemas, serializerOptsServerOption) { // 此工厂函数必须返回一个模式序列化器编译器。 // 详情请参阅 [模式序列化器](./Validation-and-Serialization.md#schema-serializer) return function 序列化器编译器 ({ schema, method, url, httpStatus, contentType }) { return data => JSON.stringify(data) } } } } });

设置404处理程序

fastify.setNotFoundHandler(handler(request, reply)): 设置404错误处理器。此调用被前缀封装,因此不同的插件可以通过传递不同的prefix选项来为不同的路径设置不同的未找到处理程序。该处理器被视为常规的路由处理器,请求将通过完整的Fastify生命周期进行处理。同时支持async-await

你也可以为404处理程序注册preValidationpreHandler钩子。

ℹ️ 注意: 使用此方法注册的preValidation钩子将在Fastify无法识别的路由上运行,而不会在手动调用reply.callNotFound时运行。在这种情况下,只有preHandler会被执行。

fastify.setNotFoundHandler({ preValidation: (req, reply, done) => { // 你的代码 done() }, preHandler: (req, reply, done) => { // 你的代码 done() } }, function (request, reply) { // 带有preValidation和preHandler钩子的默认404处理程序 }) fastify.register(function (instance, options, done) { instance.setNotFoundHandler(function (request, reply) { // 不带preValidation和preHandler钩子处理以'/v1'开头的URL请求 }) done() }, { prefix: '/v1' })
Fastify 在启动时调用 setNotFoundHandler 来添加默认的 404 处理程序,此操作发生在插件注册之前。如果您希望增强默认 404 处理程序的行为(例如通过使用插件),您可以在已注册插件的上下文中调用 `fastify.setNotFoundHandler()` > ℹ️ 注意: > 请求对象中的一些配置属性在自定义未找到处理程序内部将为 undefined。例如:`request.routeOptions.url``routeOptions.method``routeOptions.config` > 此方法的设计目的是允许调用通用的 404 路由。 > 若要返回特定路由定制化的 404 响应,您可以在响应本身中实现。

设置错误处理程序

fastify.setErrorHandler(handler(error, request, reply)): 设置一个函数,该函数在发生错误时被调用。处理器绑定到 Fastify 实例,并且是完全封装的,因此不同的插件可以设置不同的错误处理器。async-await 也受支持。

如果错误的 statusCode 小于 400,则 Fastify 会自动将其设置为 500,然后调用错误处理程序。

setErrorHandler 不会捕获:

  • onResponse 回调中抛出的错误,因为响应已经发送给客户端。请使用 onSend 回调。
  • 没有找到(404)的错误。请使用 setNotFoundHandler
fastify.setErrorHandler(function (error, request, reply) { // 记录错误 this.log.error(error) // 发送错误响应 reply.status(409).send({ ok: false }) })

如果未设置任何错误处理器,Fastify 提供了一个默认函数。可以使用 fastify.errorHandler 访问该函数,并根据其 statusCode 记录错误。

const statusCode = error.statusCode if (statusCode >= 500) { log.error(error) } else if (statusCode >= 400) { log.info(error) } else { log.error(error) }

⚠ 警告: 避免在同一作用域内多次调用 setErrorHandler。请参阅 allowErrorHandlerOverride

设置子日志工厂

fastify.setChildLoggerFactory(factory(logger, bindings, opts, rawReq)): 设置一个函数,该函数在为每个请求创建子日志实例时被调用。这允许修改或添加子日志绑定和日志选项,或者返回自定义的子日志实现。

与每次记录时使用 per-log 绑定相比,子日志绑定具有性能优势,因为它们在创建子日志时由 Pino 预先序列化。

第一个参数是父级日志实例,接着是应该传递给子日志的默认绑定和日志选项,最后是原始请求(不是 Fastify 请求对象)。该函数与 this 绑定到 Fastify 实例。

例如:

const fastify = require('fastify')({ childLoggerFactory: function (logger, bindings, opts, rawReq) { // 如果需要,从请求中计算额外的绑定 bindings.traceContext = rawReq.headers['x-cloud-trace-context'] return logger.child(bindings, opts) } })

处理程序与 Fastify 实例绑定,并且完全封装,因此不同的插件可以设置不同的日志工厂。

设置请求ID生成函数

fastify.setGenReqId(function (rawReq)) 同步函数,用于为额外的Fastify实例设置请求ID。它将接收原始传入请求作为参数。提供的函数在任何情况下都不应抛出错误。

特别是在分布式系统中,您可能希望覆盖默认的ID生成行为,以处理自定义方式生成不同的ID,以便处理不同的使用场景。例如可观测性或Webhook插件。

示例:

const fastify = require('fastify')({ genReqId: (req) => { return 'base' } }) fastify.register((instance, opts, done) => { instance.setGenReqId((req) => { // 自定义请求ID,用于 `/webhooks` return 'webhooks-id' }) done() }, { prefix: '/webhooks' }) fastify.register((instance, opts, done) => { instance.setGenReqId((req) => { // 自定义请求ID,用于 `/observability` return 'observability-id' }) done() }, { prefix: '/observability' })

处理程序绑定到Fastify实例,并且完全封装,因此不同的插件可以设置不同的请求ID。

添加约束策略

用于添加自定义约束策略的函数。要注册一种新的约束类型,您必须添加一个新的约束策略,该策略知道如何将值与处理程序匹配,并且知道如何从请求中获取约束值。

使用 fastify.addConstraintStrategy 方法添加自定义约束策略:

const customResponseTypeStrategy = { // 约束策略名称,在路由处理器的 `constraints` 选项中引用 name: 'accept', // 存储工厂,用于在 find-my-way 路由树中存储路由 storage: function () { let handlers = {} return { get: (type) => { return handlers[type] || null }, set: (type, store) => { handlers[type] = store } } }, // 获取每个传入请求的约束值的函数 deriveConstraint: (req, ctx) => { return req.headers['accept'] }, // 可选标志,标记没有约束处理程序是否可以匹配具有此约束值的请求 mustMatchWhenDerived: true } const router = Fastify(); router.addConstraintStrategy(customResponseTypeStrategy);

检查约束策略是否存在

fastify.hasConstraintStrategy(strategyName) 方法用于检查是否已经存在具有相同名称的自定义约束策略。

打印路由

fastify.printRoutes(): Fastify 路由器为每个 HTTP 方法构建一个路由树。如果你调用 prettyPrint 不指定 HTTP 方法,它会将所有树合并成一棵并进行打印。合并后的树并不表示内部路由器的结构。不要用于调试。

请在 ready 调用内或之后调用此方法。

fastify.get('/test', () => {}) fastify.get('/test/hello', () => {}) fastify.get('/testing', () => {}) fastify.get('/testing/:param', () => {}) fastify.put('/update', () => {}) fastify.ready(() => { console.log(fastify.printRoutes()) // └── / // ├── test (GET) // │ ├── /hello (GET) // │ └── ing (GET) // │ └── / // │ └── :param (GET) // └── update (PUT) })

如果你想打印内部路由器树,应该指定 method 参数。打印的树将表示内部路由器结构。 可以用于调试。

console.log(fastify.printRoutes({ method: 'GET' })) // └── / // └── test (GET) // ├── /hello (GET) // └── ing (GET) // └── / // └── :param (GET) console.log(fastify.printRoutes({ method: 'PUT' })) // └── / // └── update (PUT)

fastify.printRoutes({ commonPrefix: false }) 将打印压缩后的树。当你有许多具有公共前缀的路由时,这可能很有用。 它并不表示内部路由器结构。不要用于调试。

console.log(fastify.printRoutes({ commonPrefix: false })) // ├── /test (GET) // │ ├── /hello (GET) // │ └── ing (GET) // │ └── /:param (GET) // └── /update (PUT)

fastify.printRoutes({ includeMeta: (true | []) }) 将显示每个路由的 route.store 对象中的属性。这可以是一个键数组(例如 ['onRequest', Symbol('key')]),或者设置为 true 以显示所有属性。简写选项 fastify.printRoutes({ includeHooks: true }) 将包含所有的 钩子

fastify.get('/test', () => {}) fastify.get('/test/hello', () => {}) const onTimeout = () => {} fastify.addHook('onRequest', () => {}) fastify.addHook('onTimeout', onTimeout) console.log(fastify.printRoutes({ includeHooks: true, includeMeta: ['errorHandler'] })) // └── / // └── test (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (errorHandler) "defaultErrorHandler()" // test (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // • (errorHandler) "defaultErrorHandler()" // └── /hello (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (errorHandler) "defaultErrorHandler()" // /hello (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // • (errorHandler) "defaultErrorHandler()"
console.log(fastify.printRoutes({ includeHooks: true })) // └── / // └── test (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // test (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // └── /hello (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // /hello (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"]

打印插件

fastify.printPlugins(): 输出 avvio 使用的内部插件树表示,有助于调试 require 顺序问题。

请在 ready 调用内或之后调用它。

fastify.register(async function foo (instance) { instance.register(async function bar () {}) }) fastify.register(async function baz () {}) fastify.ready(() => { console.error(fastify.printPlugins()) // 将输出以下内容到 stderr: // └── root // ├── foo // │ └── bar // └── baz })

添加内容类型解析器

fastify.addContentTypeParser(content-type, options, parser) 用于为给定的内容类型传递自定义解析器。对于添加自定义内容类型的解析器很有用,例如 text/json, application/vnd.oasis.opendocument.textcontent-type 可以是字符串、字符串数组或正则表达式。

// getDefaultJsonParser 的两个参数分别用于原型中毒和构造函数中毒配置。可能的值为 'ignore', 'remove', 'error'。ignore 会跳过所有验证,类似于直接调用 JSON.parse()。有关更多信息,请参阅 // [`secure-json-parse` 文档](https://github.com/fastify/secure-json-parse#api) fastify.addContentTypeParser('text/json', { asString: true }, fastify.getDefaultJsonParser('ignore', 'ignore'))

检查内容类型解析器是否存在

fastify.hasContentTypeParser(contentType) 用于检查当前上下文中是否为指定的内容类型存在内容类型解析器。

fastify.hasContentTypeParser('text/json') fastify.hasContentTypeParser(/^.+\/json$/)

移除内容类型解析器

fastify.removeContentTypeParser(contentType) 用于在当前上下文中移除内容类型的解析器。此方法允许例如移除 application/jsontext/plain 的内置解析器。

fastify.removeContentTypeParser('application/json') fastify.removeContentTypeParser(['application/json', 'text/plain'])

移除所有内容类型解析器

fastify.removeAllContentTypeParsers() 方法允许在当前上下文中移除所有的内容类型解析器。此方法的一个应用场景是实现通配内容类型解析器。在使用 fastify.addContentTypeParser() 添加该解析器之前,可以调用 removeAllContentTypeParsers 方法。

有关不同内容类型解析器 API 的使用详情,请参阅 此处

获取默认 JSON 解析器

fastify.getDefaultJsonParser(onProtoPoisoning, onConstructorPoisoning) 接受两个参数。第一个参数是 ProtoType 毒害配置,第二个参数是构造函数毒害配置。有关更多详细信息,请参阅 secure-json-parse 文档

默认文本解析器

fastify.defaultTextParser() 可用于将内容作为纯文本进行解析。

fastify.addContentTypeParser('text/json', { asString: true }, fastify.defaultTextParser)

错误处理程序

fastify.errorHandler 可以使用 fastify 的默认错误处理器来处理错误。

fastify.get('/', { errorHandler: (error, request, reply) => { if (error.code === 'SOMETHING_SPECIFIC') { reply.send({ custom: 'response' }) return } fastify.errorHandler(error, request, response) } }, handler)

childLoggerFactory

fastify.childLoggerFactory 返回自定义的日志工厂函数,用于 Fastify 实例。更多详情请参阅 childLoggerFactory 配置选项

Symbol.asyncDispose

fastify[Symbol.asyncDispose] 是一个符号,可以用来定义一个异步函数,在 Fastify 实例关闭时调用该函数。

通常与 TypeScript 的 using 关键字一起使用,以确保在 Fastify 实例关闭后清理资源。

这非常适合短生命周期的进程或单元测试,在这些场景中必须在从函数内部返回后关闭所有 Fastify 资源。

test('Uses app and closes it afterwards', async () => { await using app = fastify(); // 使用 app 进行操作。 })

在上述示例中,Fastify 在测试完成后会自动关闭。

了解更多关于 ECMAScript 显式资源管理 using 关键字  (在 TypeScript 5.2 中引入)。

初始化配置

fastify.initialConfig: 暴露一个只读的冻结对象,该对象注册了用户传递给Fastify实例的初始选项。

当前可以暴露的属性包括:

  • connectionTimeout
  • keepAliveTimeout
  • bodyLimit
  • caseSensitive
  • allowUnsafeRegex
  • http2
  • https(如果显式传递,则返回 false/true{ allowHTTP1: true/false }
  • ignoreTrailingSlash
  • disableRequestLogging
  • maxParamLength
  • onProtoPoisoning
  • onConstructorPoisoning
  • pluginTimeout
  • requestIdHeader
  • requestIdLogLabel
  • http2SessionTimeout
  • useSemicolonDelimiter
const { readFileSync } = require('node:fs') const Fastify = require('fastify') const fastify = Fastify({ https: { allowHTTP1: true, key: readFileSync('./fastify.key'), cert: readFileSync('./fastify.cert') }, logger: { level: 'trace'}, ignoreTrailingSlash: true, maxParamLength: 200, caseSensitive: true, trustProxy: '127.0.0.1,192.168.1.1/24', }) console.log(fastify.initialConfig) /* 将打印: { caseSensitive: true, https: { allowHTTP1: true }, ignoreTrailingSlash: true, maxParamLength: 200 } */ fastify.register(async (instance, opts) => { instance.get('/', async (request, reply) => { return instance.initialConfig /* 将返回: { caseSensitive: true, https: { allowHTTP1: true }, ignoreTrailingSlash: true, maxParamLength: 200 } */ }) instance.get('/error', async (request, reply) => { // 因为 initialConfig 是只读的,不能被修改,所以会抛出错误 instance.initialConfig.https.allowHTTP1 = false return instance.initialConfig }) }) // 开始监听。 fastify.listen({ port: 3000 }, (err) => { if (err) { fastify.log.error(err) process.exit(1) } })