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

服务器

工厂

Fastify 模块导出一个工厂函数,用于创建新的

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

http

  • 默认值: null

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

如果选项 http2https 已设置,则忽略此选项。

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
})

// registers both "/foo" and "/foo/"
fastify.get('/foo/', function (req, reply) {
reply.send('foo')
})

// registers both "/bar" and "/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
})

// registers "/foo/bar/"
fastify.get('///foo//bar//', function (req, reply) {
reply.send('foo')
})

maxParamLength

  • 默认值: 100

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

这在您拥有基于正则表达式的路由时尤其有用,可以保护您免受 ReDoS 攻击

bodyLimit

  • 默认值: 1048576(1MiB)

定义服务器允许接受的最大有效负载(以字节为单位)。如果主体的尺寸超过此限制,则默认主体读取器会发送 FST_ERR_CTP_BODY_TOO_LARGE 响应。如果提供了 preParsing 钩子,则此限制将应用于钩子返回的流的大小(即“解码”主体的尺寸)。

onProtoPoisoning

  • 默认值: 'error'

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

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

onConstructorPoisoning

  • 默认值: 'error'

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

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

logger

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

此属性可能具有的可能值为

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

  • pinoInstance:先前实例化的 Pino 实例。内部日志记录器将指向此实例。

  • object:标准 Pino 选项对象。这将直接传递给 Pino 构造函数。如果对象上不存在以下属性,则将相应地添加它们

    • level:最低日志记录级别。如果未设置,则将其设置为 'info'
    • serializers: 一个序列化函数的哈希表。默认情况下,会为 req(传入的请求对象)、res(传出的响应对象)和 err(标准的 Error 对象)添加序列化器。当日志方法接收到包含这些属性中的任何一个的对象时,就会使用相应的序列化器处理该属性。例如
      fastify.get('/foo', function (req, res) {
      req.log.info({req}) // log the serialized request object
      res.send('foo')
      })
      任何用户提供的序列化器都会覆盖对应属性的默认序列化器。
  • loggerInstance: 一个自定义的日志记录器实例。该日志记录器必须符合 Pino 接口,即拥有以下方法:infoerrordebugfatalwarntracechild。例如

    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 发出的其他日志消息将保持启用状态,例如弃用警告和在服务器关闭时收到请求时发出的消息。

// Examples of hooks to replicate the disabled functionality.
fastify.addHook('onRequest', (req, reply, done) => {
req.log.info({ url: req.raw.url, id: req.id }, 'received request')
done()
})

fastify.addHook('onResponse', (req, reply, done) => {
req.log.info({ url: req.raw.originalUrl, statusCode: reply.raw.statusCode }, 'request completed')
done()
})

serverFactory

您可以通过使用 serverFactory 选项向 Fastify 传递一个自定义的 HTTP 服务器。

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。如果不是,您可以在 return 语句之前,在 serverFactory 函数内部增强服务器实例。

caseSensitive

  • 默认值:true

当设置为 true 时,路由将被注册为区分大小写。也就是说,/foo 不等于 /Foo。当设置为 false 时,路由将不区分大小写。

请注意,将此选项设置为 false 违反了 RFC3986

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

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

allowUnsafeRegex

  • 默认值:false

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

fastify.get('/user/:id(^([0-9]+){4}$)', (request, reply) => {
// Throws an error without allowUnsafeRegex = true
})

requestIdHeader

  • 默认值:'request-id'

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

  • 默认值: false
const fastify = require('fastify')({
requestIdHeader: 'x-custom-id', // -> use 'X-Custom-Id' header if available
//requestIdHeader: false, // -> always use genReqId
})

requestIdLogLabel

  • 默认值:'reqId'

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

genReqId

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

用于生成请求 ID 的函数。它将接收原始的传入请求作为参数。此函数预期不会出错。

尤其是在分布式系统中,您可能希望覆盖默认的 ID 生成行为,如下所示。对于生成 UUID,您可能需要查看 hyperid

注意 如果在

[requestIdHeader](#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 })

有关更多示例,请参阅 proxy-addr 包。

您可以在 request 对象上访问 ipipshostprotocol 值。

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 时,禁用此检查。这控制 avviotimeout 参数。

querystringParser

Fastify 使用的默认查询字符串解析器是 Node.js 的核心 querystring 模块。

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

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

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

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

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

exposeHeadRoutes

  • 默认值:true

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

constraints

Fastify 的内置路由约束由 find-my-way 提供,它允许通过 versionhost 来约束路由。您可以添加新的约束策略,或覆盖内置策略,方法是提供一个 constraints 对象,其中包含 find-my-way 的策略。您可以在 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' // Refer to [ajv options](https://ajv.js.org/options.html#removeadditional)
},
plugins: [
require('ajv-merge-patch'),
[require('ajv-keywords'), 'instanceof']
// Usage: [plugin, pluginOptions] - Plugin with options
// Usage: plugin - Plugin without options
]
}
})

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("Provided url is not valid")
} else if(error instanceof FST_ERR_ASYNC_CONSTRAINT) {
res.code(400)
return res.send("Provided header is not valid")
} else {
res.send(err)
}
}
})

clientErrorHandler

设置一个 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 }, 'client error')

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: 'Client error',
code: '400'
}
})

// `this` is bound to fastify instance
this.log.trace({ err }, 'client error')

// the handler is responsible for generating a valid HTTP response
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 The raw Node.js HTTP request, not the `FastifyRequest` object.
// @this Fastify The root Fastify instance (not an encapsulated instance).
// @returns {string} The path that the request should be mapped to.
function rewriteUrl (req) {
if (req.url === '/hi') {
this.log.debug({ originalUrl: req.url, url: '/hello' }, 'rewrite 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) => {
// An example request such as `/dev;foo=bar`
// Will produce the following query params result `{ foo = 'bar' }`
return request.query
})

实例

服务器方法

服务器

fastify.server:Node 核心 服务器 对象,由 Fastify 工厂函数 返回。

警告 如果使用不当,某些 Fastify 功能可能会受到干扰。建议仅将其用于附加监听器。

after

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

fastify
.register((instance, opts, done) => {
console.log('Current plugin')
done()
})
.after(err => {
console.log('After current plugin')
})
.register((instance, opts, done) => {
console.log('Next plugin')
done()
})
.ready(err => {
console.log('Everything has been loaded')
})

如果after()在没有函数的情况下被调用,它会返回一个Promise

fastify.register(async (instance, opts) => {
console.log('Current plugin')
})

await fastify.after()
console.log('After current plugin')

fastify.register(async (instance, opts) => {
console.log('Next plugin')
})

await fastify.ready()

console.log('Everything has been loaded')

ready

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

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

如果它在没有任何参数的情况下被调用,它将返回一个Promise

fastify.ready().then(() => {
console.log('successfully booted!')
}, (err) => {
console.log('an error happened', err)
})

listen

启动服务器并在内部等待.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 地址上监听。下表详细说明了针对localhosthost的可能值,以及这些host值的相应结果。

主机IPv4IPv6
::*
:: + ipv6Only🚫
0.0.0.0🚫
localhost
127.0.0.1🚫
::1🚫
* 使用地址::将在所有 IPv6 地址上监听,并且根据操作系统,也可能监听[所有 IPv4 地址](https://node.org.cn/api/net.html#serverlistenport-host-backlog-callback)。

在决定监听所有接口时要小心;它存在固有的 安全风险

默认情况下,监听端口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)
}
})

如果没有提供回调,则返回 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) => {})

addresses

此方法返回服务器正在监听的一组地址。如果在调用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()

routing

用于访问内部路由器的lookup方法并将请求与相应的处理程序匹配的方法

fastify.routing(req, res)

route

用于向服务器添加路由的方法,它还具有简写函数,请查看 此处

hasRoute

用于检查路由是否已注册到内部路由器的方法。它期望一个对象作为有效负载。urlmethod是必填字段。还可以指定constraints。如果路由已注册,则该方法返回true;否则返回false

const routeExists = fastify.hasRoute({
url: '/',
method: 'GET',
constraints: { version: '1.0.0' } // optional
})

if (routeExists === false) {
// add route
}

findRoute

用于检索已注册到内部路由器的路由的方法。它期望一个对象作为有效负载。urlmethod是必填字段。还可以指定constraints。该方法返回一个路由对象,如果找不到路由则返回null

const route = fastify.findRoute({
url: '/artists/:artistId',
method: 'GET',
constraints: { version: '1.0.0' } // optional
})

if (route !== null) {
// perform some route checks
console.log(route.params) // `{artistId: ':artistId'}`
}

close

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

调用close也将导致服务器以503错误响应每个新的传入请求并销毁该请求。有关更改此行为,请参阅 return503OnClosing标志

如果它在没有任何参数的情况下被调用,它将返回一个 Promise

fastify.close().then(() => {
console.log('successfully closed!')
}, (err) => {
console.log('an error happened', err)
})

decorate*

如果您需要装饰 fastify 实例、Reply 或 Request,此函数很有用,请查看 此处

register

Fastify 允许用户使用插件扩展其功能。插件可以是一组路由、服务器装饰器或任何其他内容,请查看 此处

addHook

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

prefix

将作为前缀添加到路由的完整路径。

示例

fastify.register(function (instance, opts, done) {
instance.get('/foo', function (request, reply) {
// Will log "prefix: /v1"
request.log.info('prefix: %s', instance.prefix)
reply.send({ prefix: instance.prefix })
})

instance.register(function (instance, opts, done) {
instance.get('/bar', function (request, reply) {
// Will log "prefix: /v1/v2"
request.log.info('prefix: %s', instance.prefix)
reply.send({ prefix: instance.prefix })
})

done()
}, { prefix: '/v2' })

done()
}, { prefix: '/v1' })

pluginName

当前插件的名称。根插件称为'fastify'。有不同的方法来定义名称(按顺序)。

  1. 如果您使用 fastify-plugin,则使用元数据name
  2. 如果导出的插件具有Symbol.for('fastify.display-name')属性,则使用该属性的值。例如:pluginFn[Symbol.for('fastify.display-name')] = "Custom Name"
  3. 如果您module.exports一个插件,则使用文件名。
  4. 如果您使用常规的 函数声明,则使用函数名。

后备:插件的前两行将表示插件名称。换行符将替换为--。这将有助于在处理许多插件时识别根本原因。

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

hasPlugin

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

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

fastify.ready(() => {
fastify.hasPlugin('@fastify/cookie') // true
})

listeningOrigin

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

log

日志记录器实例,请查看 此处

version

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

inject

伪造 HTTP 注入(用于测试目的) 此处

addHttpMethod

Fastify 默认支持GETHEADTRACEDELETEOPTIONSPATCHPUTPOST HTTP 方法。addHttpMethod方法允许向服务器添加任何非标准的 HTTP 方法,这些方法 受 Node.js 支持

// Add a new HTTP method called 'MKCOL' that supports a request body
fastify.addHttpMethod('MKCOL', { hasBody: true, })

// Add a new HTTP method called 'COPY' that does not support a request body
fastify.addHttpMethod('COPY')

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

fastify.addHttpMethod('MKCOL', { hasBody: true })
fastify.mkcol('/', (req, reply) => {
// Handle the 'MKCOL' request
})

addSchema

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

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

getSchemas

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

getSchema

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

setReplySerializer

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

fastify.setReplySerializer(function (payload, statusCode){
// serialize the payload with a sync function
return `my serialized ${statusCode} content: ${payload}`
})

setValidatorCompiler

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

setSchemaErrorFormatter

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

setSerializerCompiler

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

注意 如果设置了 setReplySerializer,则它具有优先级!

validatorCompiler

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

serializerCompiler

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

schemaErrorFormatter

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

schemaController

此属性可用于完全管理

  • bucket:应用程序的模式将存储在其中
  • compilersFactory:哪个模块必须编译 JSON 模式

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

另一个用例是调整所有模式处理。这样做可以利用 Ajv v8 JTD 或独立功能。要使用 JTD 或独立模式等,请参阅 @fastify/ajv-compiler 文档

const fastify = Fastify({
schemaController: {
/**
* This factory is called whenever `fastify.register()` is called.
* It may receive as input the schemas of the parent context if some schemas have been added.
* @param {object} parentSchemas these schemas will be returned by the
* `getSchemas()` method function of the returned `bucket`.
*/
bucket: function factory (parentSchemas) {
return {
add (inputSchema) {
// This function must store the schema added by the user.
// This function is invoked when `fastify.addSchema()` is called.
},
getSchema (schema$id) {
// This function must return the raw schema requested by the `schema$id`.
// This function is invoked when `fastify.getSchema(id)` is called.
return aSchema
},
getSchemas () {
// This function must return all the schemas referenced by the routes schemas' $ref
// It must return a JSON where the property is the schema `$id` and the value is the raw JSON Schema.
const allTheSchemaStored = {
'schema$id1': schema1,
'schema$id2': schema2
}
return allTheSchemaStored
}
}
},

/**
* The compilers factory lets you fully control the validator and serializer
* in the Fastify's lifecycle, providing the encapsulation to your compilers.
*/
compilersFactory: {
/**
* This factory is called whenever a new validator instance is needed.
* It may be called whenever `fastify.register()` is called only if new schemas have been added to the
* encapsulation context.
* It may receive as input the schemas of the parent context if some schemas have been added.
* @param {object} externalSchemas these schemas will be returned by the
* `bucket.getSchemas()`. Needed to resolve the external references $ref.
* @param {object} ajvServerOption the server `ajv` options to build your compilers accordingly
*/
buildValidator: function factory (externalSchemas, ajvServerOption) {
// This factory function must return a schema validator compiler.
// See [#schema-validator](./Validation-and-Serialization.md#schema-validator) for details.
const yourAjvInstance = new Ajv(ajvServerOption.customOptions)
return function validatorCompiler ({ schema, method, url, httpPart }) {
return yourAjvInstance.compile(schema)
}
},

/**
* This factory is called whenever a new serializer instance is needed.
* It may be called whenever `fastify.register()` is called only if new schemas have been added to the
* encapsulation context.
* It may receive as input the schemas of the parent context if some schemas have been added.
* @param {object} externalSchemas these schemas will be returned by the
* `bucket.getSchemas()`. Needed to resolve the external references $ref.
* @param {object} serializerOptsServerOption the server `serializerOpts`
* options to build your compilers accordingly
*/
buildSerializer: function factory (externalSchemas, serializerOptsServerOption) {
// This factory function must return a schema serializer compiler.
// See [#schema-serializer](./Validation-and-Serialization.md#schema-serializer) for details.
return function serializerCompiler ({ schema, method, url, httpStatus, contentType }) {
return data => JSON.stringify(data)
}
}
}
}
});

setNotFoundHandler

fastify.setNotFoundHandler(handler(request, reply)):设置 404 处理程序。此调用由前缀封装,因此如果将不同的 prefix 选项 传递给 fastify.register(),则不同的插件可以设置不同的未找到处理程序。处理程序被视为常规路由处理程序,因此请求将经历完整的 Fastify 生命周期。也支持async-await

您还可以为 404 处理程序注册 preValidationpreHandler 钩子。

注意 使用此方法注册的 preValidation 钩子将针对 Fastify 无法识别的路由运行,而不会在路由处理程序手动调用 reply.callNotFound 时运行。在这种情况下,只会运行 preHandler。

fastify.setNotFoundHandler({
preValidation: (req, reply, done) => {
// your code
done()
},
preHandler: (req, reply, done) => {
// your code
done()
}
}, function (request, reply) {
// Default not found handler with preValidation and preHandler hooks
})

fastify.register(function (instance, options, done) {
instance.setNotFoundHandler(function (request, reply) {
// Handle not found request without preValidation and preHandler hooks
// to URLs that begin with '/v1'
})
done()
}, { prefix: '/v1' })

Fastify 在启动时调用 setNotFoundHandler 以添加默认的 404 处理程序,然后再注册插件。如果您想增强默认 404 处理程序的行为(例如使用插件),则可以在这些已注册插件的上下文中不带参数调用 setNotFoundHandler fastify.setNotFoundHandler()

注意 请求对象中的一些配置属性在自定义未找到处理程序内部将未定义。例如:request.routerPathrouterMethodcontext.config。此方法的设计目标是允许调用常见的未找到路由。要返回每个路由的自定义 404 响应,您可以在响应本身中执行此操作。

setErrorHandler

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

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

setErrorHandler **不会** 捕获

  • onResponse 钩子中抛出的错误,因为响应已发送到客户端。请改用 onSend 钩子。
  • 未找到 (404) 错误。请改用 setNotFoundHandler
fastify.setErrorHandler(function (error, request, reply) {
// Log error
this.log.error(error)
// Send error response
reply.status(409).send({ ok: false })
})

如果未设置错误处理程序,则 Fastify 会提供一个默认函数。可以通过 fastify.errorHandler 访问它,并且它会根据其 statusCode 记录错误。

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

setChildLoggerFactory

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

子日志记录器绑定比每个日志绑定具有性能优势,因为它们在创建子日志记录器时由 Pino 预序列化。

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

例如

const fastify = require('fastify')({
childLoggerFactory: function (logger, bindings, opts, rawReq) {
// Calculate additional bindings from the request if needed
bindings.traceContext = rawReq.headers['x-cloud-trace-context']
return logger.child(bindings, opts)
}
})

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

setGenReqId

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) => {
// custom request ID for `/webhooks`
return 'webhooks-id'
})
done()
}, { prefix: '/webhooks' })

fastify.register((instance, opts, done) => {
instance.setGenReqId((req) => {
// custom request ID for `/observability`
return 'observability-id'
})
done()
}, { prefix: '/observability' })

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

addConstraintStrategy

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

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

const customResponseTypeStrategy = {
// strategy name for referencing in the route handler `constraints` options
name: 'accept',
// storage factory for storing routes in the find-my-way route tree
storage: function () {
let handlers = {}
return {
get: (type) => { return handlers[type] || null },
set: (type, store) => { handlers[type] = store }
}
},
// function to get the value of the constraint from each incoming request
deriveConstraint: (req, ctx) => {
return req.headers['accept']
},
// optional flag marking if handlers without constraints can match requests that have a value for this constraint
mustMatchWhenDerived: true
}

const router = Fastify();
router.addConstraintStrategy(customResponseTypeStrategy);

hasConstraintStrategy

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

printRoutes

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 对象中的属性。这可以是键的 array(例如 ['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()"]

printPlugins

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())
// will output the following to stderr:
// └── root
// ├── foo
// │ └── bar
// └── baz
})

addContentTypeParser

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

// The two arguments passed to getDefaultJsonParser are for ProtoType poisoning
// and Constructor Poisoning configuration respectively. The possible values are
// 'ignore', 'remove', 'error'. ignore skips all validations and it is similar
// to calling JSON.parse() directly. See the
// [`secure-json-parse` documentation](https://github.com/fastify/secure-json-parse#api) for more information.

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

hasContentTypeParser

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

fastify.hasContentTypeParser('text/json')

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

removeContentTypeParser

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

fastify.removeContentTypeParser('application/json')

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

removeAllContentTypeParsers

fastify.removeAllContentTypeParsers() 方法允许删除当前上下文中的所有内容类型解析器。此方法的用例是 catch-all 内容类型解析器的实现。在使用 fastify.addContentTypeParser() 添加此解析器之前,可以调用 removeAllContentTypeParsers 方法。

有关不同内容类型解析器 API 用法的更多详细信息,请参阅 此处

getDefaultJsonParser

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

defaultTextParser

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

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

errorHandler

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();
// do something with app.
})

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

阅读有关ECMAScript 显式资源管理和 TypeScript 5.2 中引入的using 关键字的更多信息。

initialConfig

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

当前可以公开的属性为

  • 连接超时
  • 保持活动超时
  • 主体限制
  • 区分大小写
  • 允许不安全的正则表达式
  • http2
  • https(如果显式传递,它将返回false/true{ allowHTTP1: true/false }
  • 忽略尾部斜杠
  • 禁用请求日志记录
  • 最大参数长度
  • 处理原型污染
  • 处理构造函数污染
  • 插件超时
  • 请求 ID 标头
  • 请求 ID 日志标签
  • HTTP/2 会话超时
  • 使用分号分隔符
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)
/*
will log :
{
caseSensitive: true,
https: { allowHTTP1: true },
ignoreTrailingSlash: true,
maxParamLength: 200
}
*/

fastify.register(async (instance, opts) => {
instance.get('/', async (request, reply) => {
return instance.initialConfig
/*
will return :
{
caseSensitive: true,
https: { allowHTTP1: true },
ignoreTrailingSlash: true,
maxParamLength: 200
}
*/
})

instance.get('/error', async (request, reply) => {
// will throw an error because initialConfig is read-only
// and can not be modified
instance.initialConfig.https.allowHTTP1 = false

return instance.initialConfig
})
})

// Start listening.
fastify.listen({ port: 3000 }, (err) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})