服务器
工厂
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
})
// 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 中的重复斜杠。此选项适用于生成的服务器实例的所有路由注册。
当 ignoreTrailingSlash
和 ignoreDuplicateSlashes
都设置为 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 接口,即拥有以下方法: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
,可以禁用这些日志消息。这允许通过附加自定义的 onRequest
和 onResponse
钩子来实现更灵活的请求开始和结束日志记录。
其他将被禁用的日志条目包括:
- 默认
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
参数,该参数以 request
和 response
对象作为参数,以及一个选项对象,该对象与您传递给 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
对象上访问 ip
、ips
、host
和 protocol
值。
fastify.get('/', (request, reply) => {
console.log(request.ip)
console.log(request.ips)
console.log(request.host)
console.log(request.protocol)
})
注意 如果请求包含多个
x-forwarded-host
或x-forwarded-proto
标头,则仅使用最后一个标头来推导出request.hostname
和request.protocol
。
pluginTimeout
- 默认值:
10000
插件加载的最大时间(以毫秒为单位)。如果超过此时间,ready
将使用代码为 'ERR_AVVIO_PLUGIN_TIMEOUT'
的 Error
完成。当设置为 0
时,禁用此检查。这控制 avvio 的 timeout
参数。
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
提供,它允许通过 version
或 host
来约束路由。您可以添加新的约束策略,或覆盖内置策略,方法是提供一个 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_URL
和FST_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 地址上监听。下表详细说明了针对localhost
时host
的可能值,以及这些host
值的相应结果。
主机 | IPv4 | IPv6 |
---|---|---|
:: | ✅* | ✅ |
:: + 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
用于检查路由是否已注册到内部路由器的方法。它期望一个对象作为有效负载。url
和method
是必填字段。还可以指定constraints
。如果路由已注册,则该方法返回true
;否则返回false
。
const routeExists = fastify.hasRoute({
url: '/',
method: 'GET',
constraints: { version: '1.0.0' } // optional
})
if (routeExists === false) {
// add route
}
findRoute
用于检索已注册到内部路由器的路由的方法。它期望一个对象作为有效负载。url
和method
是必填字段。还可以指定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'
。有不同的方法来定义名称(按顺序)。
- 如果您使用 fastify-plugin,则使用元数据
name
。 - 如果导出的插件具有
Symbol.for('fastify.display-name')
属性,则使用该属性的值。例如:pluginFn[Symbol.for('fastify.display-name')] = "Custom Name"
- 如果您
module.exports
一个插件,则使用文件名。 - 如果您使用常规的 函数声明,则使用函数名。
后备:插件的前两行将表示插件名称。换行符将替换为--
。这将有助于在处理许多插件时识别根本原因。
警告 如果您必须处理嵌套插件,则名称会因使用 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 默认支持GET
、HEAD
、TRACE
、DELETE
、OPTIONS
、PATCH
、PUT
和POST
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 处理程序注册 preValidation
和 preHandler
钩子。
注意 使用此方法注册的
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.routerPath
、routerMethod
和context.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.text
。content-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/json
和 text/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)
}
})