fastify.route(options)
示例:
fastify.route({
method: 'GET',
url: '/',
schema: {
querystring: {
name: { type: 'string' },
excitement: { type: 'integer' }
},
response: {
200: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
}
},
handler: function (request, reply) {
reply.send({ hello: 'world' })
}
})
上文的路由定義帶有 Hapi 的風(fēng)格。要是偏好 Express/Restify 的寫(xiě)法,F(xiàn)astify 也是支持的:fastify.get(path, [options], handler)fastify.head(path, [options], handler)fastify.post(path, [options], handler)fastify.put(path, [options], handler)fastify.delete(path, [options], handler)fastify.options(path, [options], handler)fastify.patch(path, [options], handler)
示例:
const opts = {
schema: {
response: {
200: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
}
}
}
fastify.get('/', opts, (request, reply) => {
reply.send({ hello: 'world' })
})
fastify.all(path, [options], handler) 會(huì)給所有支持的 HTTP 方法添加相同的處理函數(shù)。
處理函數(shù)還可以寫(xiě)到 options 對(duì)象里:
const opts = {
schema: {
response: {
200: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
}
},
handler (request, reply) {
reply.send({ hello: 'world' })
}
}
fastify.get('/', opts)
注:假如同時(shí)在 options 和簡(jiǎn)寫(xiě)方法的第三個(gè)參數(shù)里指明了處理函數(shù),將會(huì)拋出重復(fù)的 handler 錯(cuò)誤。
Fastify 同時(shí)支持靜態(tài)與動(dòng)態(tài)的 url。要注冊(cè)一個(gè)參數(shù)命名的路徑,請(qǐng)?jiān)趨?shù)名前加上冒號(hào)。星號(hào)表示*通配符**。 *注意,靜態(tài)路由總是在參數(shù)路由和通配符之前進(jìn)行匹配。
// 參數(shù)路由
fastify.get('/example/:userId', (request, reply) => {}))
fastify.get('/example/:userId/:secretToken', (request, reply) => {}))
// 通配符
fastify.get('/example/*', (request, reply) => {}))
正則表達(dá)式路由亦被支持。但要注意,正則表達(dá)式會(huì)嚴(yán)重拖累性能!
// 正則表達(dá)的參數(shù)路由
fastify.get('/example/:file(^\\d+).png', (request, reply) => {}))
你還可以在同一組斜杠 ("/") 里定義多個(gè)參數(shù)。就像這樣:
fastify.get('/example/near/:lat-:lng/radius/:r', (request, reply) => {}))
使用短橫線 ("-") 來(lái)分隔參數(shù)。
最后,同時(shí)使用多參數(shù)和正則表達(dá)式也是允許的。
fastify.get('/example/at/:hour(^\\d{2})h:minute(^\\d{2})m', (request, reply) => {}))
在這個(gè)例子里,任何未被正則匹配的符號(hào)均可作為參數(shù)的分隔符。
多參數(shù)的路由會(huì)影響性能,所以應(yīng)該盡量使用單參數(shù),對(duì)于高頻訪問(wèn)的路由來(lái)說(shuō)更是如此。 如果你對(duì)路由的底層感興趣,可以查看find-my-way。
你是 async/await 的使用者嗎?我們?yōu)槟憧紤]了一切!
fastify.get('/', options, async function (request, reply) {
var data = await getData()
var processed = await processData(data)
return processed
})
如你所見(jiàn),我們不再使用 reply.send 向用戶(hù)發(fā)送數(shù)據(jù),只需返回消息主體就可以了!
當(dāng)然,需要的話你還是可以使用 reply.send 發(fā)送數(shù)據(jù)。
fastify.get('/', options, async function (request, reply) {
var data = await getData()
var processed = await processData(data)
reply.send(processed)
})
假如在路由中,reply.send() 脫離了 promise 鏈,在一個(gè)基于回調(diào)的 API 中被調(diào)用,你可以使用 await reply:
fastify.get('/', options, async function (request, reply) {
setImmediate(() => {
reply.send({ hello: 'world' })
})
await reply
})
返回回復(fù)也是可行的:
fastify.get('/', options, async function (request, reply) {
setImmediate(() => {
reply.send({ hello: 'world' })
})
return reply
})
警告:
假如你的處理函數(shù)是一個(gè) async 函數(shù),或返回了一個(gè) promise,請(qǐng)注意一種必須支持回調(diào)函數(shù)和 promise 控制流的特殊情況:如果 promise 被 resolve 為 undefined,請(qǐng)求會(huì)被掛起,并觸發(fā)一個(gè)錯(cuò)誤日志。
通過(guò)這一方法,我們便可以最小代價(jià)同時(shí)支持 回調(diào)函數(shù)風(fēng)格 以及 async-await。盡管這么做十分自由,我們還是強(qiáng)烈建議僅使用其中的一種,因?yàn)閼?yīng)用的錯(cuò)誤處理方式應(yīng)當(dāng)保持一致。
注意:每個(gè) async 函數(shù)各自返回一個(gè) promise 對(duì)象。
有時(shí)你需要維護(hù)同一 api 的多個(gè)不同版本。一般的做法是在所有的路由之前加上版本號(hào),例如 /v1/user。 Fastify 提供了一個(gè)快捷且智能的方法來(lái)解決上述問(wèn)題,無(wú)需手動(dòng)更改全部路由。這就是路由前綴。讓我們來(lái)看下吧:
// server.js
const fastify = require('fastify')()
fastify.register(require('./routes/v1/users'), { prefix: '/v1' })
fastify.register(require('./routes/v2/users'), { prefix: '/v2' })
fastify.listen(3000)
// routes/v1/users.js
module.exports = function (fastify, opts, done) {
fastify.get('/user', handler_v1)
done()
}
// routes/v2/users.js
module.exports = function (fastify, opts, done) {
fastify.get('/user', handler_v2)
done()
}
在編譯時(shí) Fastify 自動(dòng)處理了前綴,因此兩個(gè)不同路由使用相同的路徑名并不會(huì)產(chǎn)生問(wèn)題。(這也意味著性能一點(diǎn)兒也不受影響!)。
現(xiàn)在,你的客戶(hù)端就可以訪問(wèn)下列路由了:
根據(jù)需要,你可以多次設(shè)置路由前綴,它也支持嵌套的 register 以及路由參數(shù)。 請(qǐng)注意,當(dāng)使用了 fastify-plugin 時(shí),這一選項(xiàng)是無(wú)效的。
根據(jù)前綴是否以 / 結(jié)束,路徑為 / 的路由的匹配模式有所不同。舉例來(lái)說(shuō),前綴為 /something/ 的 / 路由只會(huì)匹配 something,而前綴為 /something 則會(huì)匹配 /something 和 /something/。
要改變這一行為,請(qǐng)見(jiàn)上文 prefixTrailingSlash 選項(xiàng)。
在 Fastify 中為路由里設(shè)置不同的日志級(jí)別是十分容易的。你只需在插件或路由的選項(xiàng)里設(shè)置 logLevel 為相應(yīng)的值即可。
要注意的是,如果在插件層面上設(shè)置了 logLevel,那么 setNotFoundHandler 和 setErrorHandler 也會(huì)受到影響。
// server.js
const fastify = require('fastify')({ logger: true })
fastify.register(require('./routes/user'), { logLevel: 'warn' })
fastify.register(require('./routes/events'), { logLevel: 'debug' })
fastify.listen(3000)
你也可以直接將其傳給路由:
fastify.get('/', { logLevel: 'warn' }, (request, reply) => {
reply.send({ hello: 'world' })
})
自定義的日志級(jí)別僅對(duì)路由生效,通過(guò) fastify.log 訪問(wèn)的全局日志并不會(huì)受到影響。
在某些上下文里,你也許需要記錄一個(gè)大型對(duì)象,但這在其他路由中是個(gè)負(fù)擔(dān)。這時(shí),你可以定義一些序列化器 (serializer),并將它們?cè)O(shè)置在正確的上下文之上!
const fastify = require('fastify')({ logger: true })
fastify.register(require('./routes/user'), {
logSerializers: {
user: (value) => `My serializer one - ${value.name}`
}
})
fastify.register(require('./routes/events'), {
logSerializers: {
user: (value) => `My serializer two - ${value.name} ${value.surname}`
}
})
fastify.listen(3000)
你可以通過(guò)上下文來(lái)繼承序列化器:
const fastify = Fastify({
logger: {
level: 'info',
serializers: {
user (req) {
return {
method: req.method,
url: req.url,
headers: req.headers,
hostname: req.hostname,
remoteAddress: req.ip,
remotePort: req.connection.remotePort
}
}
}
}
})
fastify.register(context1, {
logSerializers: {
user: value => `My serializer father - ${value}`
}
})
async function context1 (fastify, opts) {
fastify.get('/', (req, reply) => {
req.log.info({ user: 'call father serializer', key: 'another key' })
// 打印結(jié)果: { user: 'My serializer father - call father serializer', key: 'another key' }
reply.send({})
})
}
fastify.listen(3000)
注冊(cè)一個(gè)新的處理函數(shù),你可以向其傳遞一個(gè)配置對(duì)象,并在其中使用它。
// server.js
const fastify = require('fastify')()
function handler (req, reply) {
reply.send(reply.context.config.output)
}
fastify.get('/en', { config: { output: 'hello world!' } }, handler)
fastify.get('/it', { config: { output: 'ciao mondo!' } }, handler)
fastify.listen(3000)
需要的話,你可以提供一個(gè)版本選項(xiàng),它允許你為同一個(gè)路由聲明不同的版本。版本號(hào)請(qǐng)遵循 semver 規(guī)范。Fastify 會(huì)自動(dòng)檢測(cè) Accept-Version header,并將請(qǐng)求分配給相應(yīng)的路由 (當(dāng)前尚不支持 semver 規(guī)范中的 advanced ranges 與 pre-releases 語(yǔ)法)。請(qǐng)注意,這一特性會(huì)降低路由的性能。
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: function (request, reply) {
reply.send({ hello: 'world' })
}
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.x' // 也可以是 '1.2.0' 或 '1.2.x'
}
}, (err, res) => {
// { hello: 'world' }
})
如果你聲明了多個(gè)擁有相同主版本或次版本號(hào)的版本,F(xiàn)astify 總是會(huì)根據(jù) Accept-Version header 的值選擇最兼容的版本。假如請(qǐng)求未帶有 Accept-Version header,那么將返回一個(gè) 404 錯(cuò)誤。
新建實(shí)例時(shí),可以通過(guò)設(shè)置 versioning 來(lái)自定義版本號(hào)邏輯。
更多建議: