Fastify 模塊導出了一個工廠函數(shù),可以用于創(chuàng)建新的Fastify server 實例。這個工廠函數(shù)的參數(shù)是一個配置對象,用于自定義最終生成的實例。本文描述了這一對象中可用的屬性。
設置為 true,則會使用 Node.js 原生的 HTTP/2 模塊來綁定 socket。
用于配置服務器的 TLS socket 的對象。其選項與 Node.js 原生的 createServer 方法一致。 當值為 null 時,socket 連接將不會配置 TLS。
當 http2 選項設置時,https 選項也會被應用。
Fastify 使用 find-my-way 處理路由。該選項為 true 時,尾斜杠將被省略。 這一選項應用于 server 實例上注冊的所有路由。
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')
})
你可以為通過 maxParamLength 選項為帶參路由 (無論是標準的、正則匹配的,還是復數(shù)的) 設置最大參數(shù)長度。選項的默認值為 100 字符。當使用正則匹配的路由時,這非常有用,可以幫你抵御 DoS 攻擊。當達到長度限制時,將觸發(fā) not found 路由。
定義服務器可接受的最大 payload,以字節(jié)為單位。
由 secure-json-parse 提供的功能,指定解析帶有 __proto__ 鍵的 JSON 對象時框架的行為。 更多關于原型污染 (prototype poisoning) 的內(nèi)容請看 https://hueniverse.com/a-tale-of-prototype-poisoning-2610fa170061。
允許的值為 'error'、'remove' 與 'ignore'。
由 secure-json-parse 提供的功能,指定解析帶有 constructor 的 JSON 對象時框架的行為。 更多關于原型污染的內(nèi)容請看 https://hueniverse.com/a-tale-of-prototype-poisoning-2610fa170061。
允許的值為 'error'、'remove' 與 'ignore'。
Fastify 依托 Pino 內(nèi)建了一個日志工具。該屬性用于配置日志實例。
屬性可用的值為:
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});
<a name="factory-disable-request-logging"></a>
### `disableRequestLogging`
默認情況下當開啟日志時,F(xiàn)astify 會在收到請求與發(fā)送該請求的響應時記錄 `info` 級別的日志。你可以設置該選項為 `true` 來禁用該功能。這時,通過自定義 `onRequest` 和 `onResponse` 鉤子,你能更靈活地記錄一個請求的開始與結束。
+ 默認值:`false`
```js
// 例子:通過鉤子再造被禁用的請求日志功能。
fastify.addHook('onRequest', (req, reply, done) => {
req.log.info({ url: req.req.url, id: req.id }, 'received request')
done()
})
fastify.addHook('onResponse', (req, reply, done) => {
req.log.info({ url: req.req.originalUrl, statusCode: res.res.statusCode }, 'request completed')
done()
})
通過 serverFactory 選項,你可以向 Fastify 傳遞一個自定義的 http server。serverFactory 函數(shù)的參數(shù)為 handler 函數(shù)及一個選項對象。handler 函數(shù)的參數(shù)為 request 和 response 對象,選項對象則與你傳遞給 Fastify 的一致。
const serverFactory = (handler, opts) => {
const server = http.createServer((req, res) => {
handler(req, res)
})
return server
}
const fastify = Fastify({ serverFactory, modifyCoreObjects: false })
fastify.get('/', (req, reply) => {
reply.send({ hello: 'world' })
})
fastify.listen(3000)
Fastify 內(nèi)在地使用 Node 原生 http server 的 API。因此,如果你使用一個自定義的 server,你必須保證暴露了相同的 API。不這么做的話,你可以在 serverFactory 函數(shù)內(nèi)部 return 語句之前,向 server 實例添加新的屬性。要注意的是,我們也設置了 modifyCoreObjects: false。這是因為在諸如 Google Cloud Functions 等無服務器 (serverless) 環(huán)境下,一些 Node.js 核心的屬性是不可寫的。
默認值為 true,此時路由對大小寫敏感。這就意味著 /foo 與 /Foo 是兩個不同的路由。當該選項為 false 時,路由大小寫不敏感,/foo、/Foo 以及 /FOO 都是一樣的。
將 caseSensitive 設置為 false,會導致所有路徑變?yōu)樾?,除了路由參?shù)與通配符。
fastify.get('/user/:username', (request, reply) => {
// 原 URL: /USER/NodeJS
console.log(request.params.username) // -> 'NodeJS'
})
要注意的是,將該選項設為 false 與 RFC3986 相悖。
用來獲知請求 id 的 header 名。請看請求 id 一節(jié)。
定義日志中請求 id 的標簽。
用于生成請求 id 的函數(shù)。參數(shù)為來訪的請求對象。
注意:當設置了 'request-id' header時,genReqId 不會 被調(diào)用。
通過開啟 trustProxy 選項,F(xiàn)astify 會認為使用了代理服務,且 X-Forwarded-* header 是可信的,否則該值被認為是極具欺騙性的。
const fastify = Fastify({ trustProxy: true })
更多示例詳見 proxy-addr。
你還可以通過 request 對象獲取 ip、ips 與 hostname 的值。
fastify.get('/', (request, reply) => {
console.log(request.ip)
console.log(request.ips)
console.log(request.hostname)
})
單個插件允許加載的最長時間,以毫秒計。如果某個插件加載超時,則 ready 會拋出一個含有 'ERR_AVVIO_PLUGIN_TIMEOUT' 代碼的 Error 對象。
Fastify 默認使用 Node.js 核心的 querystring 模塊作為 query string 解析器。你可以通過 querystringParser 選項來使用自定義的解析器,例如 qs。
const qs = require('qs')
const fastify = require('fastify')({
querystringParser: str => qs.parse(str)
})
默認情況下,find-my-way 使用 semver 版本號規(guī)范來為路由設置版本號。你也可以使用自定義的版本號策略。更多信息請看 find-my-way 的文檔。
const versioning = {
storage: function () {
let versions = {}
return {
get: (version) => { return versions[version] || null },
set: (version, store) => { versions[version] = store },
del: (version) => { delete versions[version] },
empty: () => { versions = {} }
}
},
deriveVersion: (req, ctx) => {
return req.headers['accept']
}
}
const fastify = require('fastify')({
versioning
})
默認情況下,F(xiàn)astify 會向 Node 原生的 request 對象添加 ip、ips、hostname 以及 log 屬性 (參見 Request),向原生的 response 對象添加 log 屬性。你可以將 modifyCoreObjects 設為 false 來避免上述行為。
const fastify = Fastify({ modifyCoreObjects: true }) // 默認值
fastify.get('/', (request, reply) => {
console.log(request.raw.ip)
console.log(request.raw.ips)
console.log(request.raw.hostname)
request.raw.log('Hello')
reply.res.log('World')
})
在諸如 Google Cloud Functions 等無服務器 (serverless) 環(huán)境下,禁用該選項是有用的。因為在這些環(huán)境中,ip 及 ips 并不可寫。
請注意,我們不建議使用這些屬性。它們將會在 Fastify 的下個主要版本中,與該選項一起去除。作為替代,我們推薦使用 Fastify 的 Request 與 Reply 對象上相同的屬性。
const fastify = Fastify({ modifyCoreObjects: false })
fastify.get('/', (request, reply) => {
console.log(request.ip)
console.log(request.ips)
console.log(request.hostname)
request.log('Hello')
reply.log('World')
})
調(diào)用 close 方法后返回 503 狀態(tài)碼。 如果為 false,服務器會正常處理請求。
配置 Fastify 使用的 ajv 實例。這使得你無需提供一個自定義的實例。
{
customOptions: {
removeAdditional: true,
useDefaults: true,
coerceTypes: true,
allErrors: true,
nullable: true
},
plugins: []
}
const fastify = require('fastify')({
ajv: {
customOptions: {
nullable: false // 參見 [ajv 的配置選項](https://ajv.js.org/#options)
},
plugins: [
require('ajv-merge-patch')
[require('ajv-keywords'), 'instanceof'];
// 用法: [plugin, pluginOptions] - 插件與選項
// 用法: plugin - 僅插件
]
}
})
fastify.server:由 Fastify 的工廠函數(shù) 生成的 Node 原生 server 對象。
當前插件及在其中注冊的所有插件加載完畢后調(diào)用??傇?nbsp;fastify.ready 之前執(zhí)行。
fastify
.register((instance, opts, done) => {
console.log('當前插件')
done()
})
.after(err => {
console.log('當前插件之后')
})
.register((instance, opts, done) => {
console.log('下一個插件')
done()
})
.ready(err => {
console.log('萬事俱備')
})
當所有插件的加載都完成時調(diào)用。如有錯誤發(fā)生,它會傳遞一個 error 參數(shù)。
fastify.ready(err => {
if (err) throw err
})
調(diào)用時不加參數(shù),它會返回一個 Promise 對象:
fastify.ready().then(() => {
console.log('successfully booted!')
}, (err) => {
console.log('an error happened', err)
})
所有的插件加載完畢、ready 事件觸發(fā)后,在指定的端口啟動服務器。它的回調(diào)函數(shù)與 Node 原生方法的回調(diào)相同。默認情況下,服務器監(jiān)聽 localhost 所決定的地址 (127.0.0.1 或 ::1,取決于操作系統(tǒng))。將地址設置為 0.0.0.0 可監(jiān)聽所有的 IPV4 地址。設置為 :: 則可監(jiān)聽所有的 IPV6 地址,在某些系統(tǒng)中,這么做亦可同時監(jiān)聽所有 IPV4 地址。監(jiān)聽所有的接口要格外謹慎,因為這種方式存在著固有的 安全風險。
fastify.listen(3000, (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
指定監(jiān)聽的地址:
fastify.listen(3000, '127.0.0.1', (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
指定積壓隊列 (backlog queue size) 的大?。?/p>
fastify.listen(3000, '127.0.0.1', 511, (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
沒有提供回調(diào)函數(shù)時,它會返回一個 Promise 對象:
fastify.listen(3000)
.then((address) => console.log(`server listening on ${address}`))
.catch(err => {
console.log('Error starting server:', err)
process.exit(1)
})
你還可以在使用 Promise 的同時指定地址:
fastify.listen(3000, '127.0.0.1')
.then((address) => console.log(`server listening on ${address}`))
.catch(err => {
console.log('Error starting server:', err)
process.exit(1)
})
當部署在 Docker 或其它容器上時,明智的做法是監(jiān)聽 0.0.0.0。因為默認情況下,這些容器并未將映射的端口暴露在 127.0.0.1:
fastify.listen(3000, '0.0.0.0', (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
假如未設置 port (或設為 0),則會自動選擇一個隨機可用的端口 (之后可通過 fastify.server.address().port 獲知)。
將路由添加到服務器的方法,支持簡寫。請看這里。
fastify.close(callback):調(diào)用這個函數(shù)來關閉服務器實例,并觸發(fā) 'onClose' 鉤子。服務器會向所有新的請求發(fā)送 503 錯誤,并銷毀它們。 要改變這一行為,請見 return503OnClosing。
如果無參調(diào)用,它會返回一個 Promise:
fastify.close().then(() => {
console.log('successfully closed!')
}, (err) => {
console.log('an error happened', err)
})
向 Fastify 實例、響應或請求添加裝飾器函數(shù)。參閱這里了解更多。
Fastify 允許用戶通過插件擴展功能。插件可以是一組路由、裝飾器或其他。請看這里。
向 Fastify 添加中間件,請看這里。
向 Fastify 添加特定的生命周期鉤子函數(shù),請看這里。
添加在路由前的完整路徑。
示例:
fastify.register(function (instance, opts, done) {
instance.get('/foo', function (request, reply) {
// 輸出:"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) {
// 輸出:"prefix: /v1/v2"
request.log.info('prefix: %s', instance.prefix)
reply.send({prefix: instance.prefix})
})
done()
}, { prefix: '/v2' })
done()
}, { prefix: '/v1' })
當前插件的名稱。有三種定義插件名稱的方式(按順序)。
回退方案:插件函數(shù)的頭兩行將作為插件名,并使用 -- 替代換行符。這有助于在處理涉及許多插件的問題時,找到根源。
重點:如果你要處理一些通過 fastify-plugin 包裝的嵌套的異名插件,由于沒有生成新的定義域,因此不會去覆蓋上下文數(shù)據(jù),而是將各插件名加入一個數(shù)組。在這種情況下,會按涉及到的插件的啟動順序,以 plugin-A -> plugin-B 的格式來展示插件名稱。
日志的實例,詳見這里。
偽造 http 注入 (作為測試之用) 。請看更多內(nèi)容。
fastify.addSchema(schemaObj),向 Fastify 實例添加可共用的 schema,用于驗證數(shù)據(jù)。你可以通過該 schema 的 id 在應用的任意位置使用它。請看驗證和序列化一文中的范例。
作用于未設置 Reply.serializer(func) 的所有路由的默認序列化方法。這個處理函數(shù)是完全封裝的,因此,不同的插件允許有不同的錯誤處理函數(shù)。 注:僅當狀態(tài)碼為 2xx 時才被調(diào)用。關于錯誤處理,請看 setErrorHandler。
fastify.setReplySerializer(function (payload, statusCode){
// 使用同步函數(shù)序列化 payload
return `my serialized ${statusCode} content: ${payload}`
})
為所有的路由設置 schema 編譯器 (schema compiler),請看這里了解更多信息。
為所有的路由設置 schema $ref 解析器 (schema $ref resolver),請看這里了解更多信息。
setSchemaCompiler 方法的簡寫。用于設置 schema 編譯器函數(shù),也可用于返回全部路由的 schema 編譯器。
fastify.setNotFoundHandler(handler(request, reply)):為 404 狀態(tài) (not found) 設置處理函數(shù) (handler)。向 fastify.register() 傳遞不同的 prefix 選項,就可以為不同的插件設置不同的處理函數(shù)。這些處理函數(shù)被視為常規(guī)的路由處理函數(shù),因此它們的請求會經(jīng)歷一個完整的 Fastify 生命周期。
你也可以為 404 處理函數(shù)注冊一個 preValidation 或 preHandler 鉤子。
fastify.setNotFoundHandler({
preValidation: (req, reply, done) => {
// 你的代碼
done()
} ,
preHandler: (req, reply, done) => {
// 你的代碼
done()
}
}, function (request, reply) {
// 設置了 preValidation 與 preHandler 鉤子的默認 not found 處理函數(shù)
})
fastify.register(function (instance, options, done) {
instance.setNotFoundHandler(function (request, reply) {
// '/v1' 開頭的 URL 的 not found 處理函數(shù),
// 未設置 preValidation 與 preHandler 鉤子
})
done()
}, { prefix: '/v1' })
fastify.setErrorHandler(handler(error, request, reply)):設置任意時刻的錯誤處理函數(shù)。錯誤處理函數(shù)是完全封裝 (fully encapsulated) 的,因此不同插件的處理函數(shù)可以不同。支持 async-await 語法。注:假如錯誤的 statusCode 小于 400,在處理錯誤前 Fastify 將會自動將其設為 500。
fastify.setErrorHandler(function (error, request, reply) {
// 記錄錯誤
// 發(fā)送錯誤響應
})
當沒有設置錯誤處理函數(shù)時,F(xiàn)astify 會調(diào)用一個默認函數(shù),并根據(jù) statusCode 相應地記錄日志:
var statusCode = error.statusCode
if (statusCode >= 500) {
log.error(error)
} else if (statusCode >= 400) {
log.info(error)
} else {
log.error(error)
}
fastify.printRoutes():打印路由的基數(shù)樹 (radix tree),可作調(diào)試之用。記得在 ready 函數(shù)的內(nèi)部或之后調(diào)用它。
fastify.get('/test', () => {})
fastify.get('/test/hello', () => {})
fastify.get('/hello/world', () => {})
fastify.ready(() => {
console.log(fastify.printRoutes())
// └── /
// ├── test (GET)
// │ └── /hello (GET)
// └── hello/world (GET)
})
更多建議: