想給 Fastify 實(shí)例新增功能?decorate 正是你所需要的 API!
decorate 允許你向 Fastify 實(shí)例添加新的屬性。屬性的值的類型沒有限制,可以是函數(shù)、對(duì)象、字符串等。
decorate 你只需調(diào)用 decorate 函數(shù),并將新屬性的名稱與值作為參數(shù)傳遞即可。
fastify.decorate('utility', () => {
// 新功能的代碼
})
正如上文所述,你還可以傳遞非函數(shù)的值:
fastify.decorate('conf', {
db: 'some.db',
port: 3000
})
一旦添加了一個(gè)裝飾器,你就可以通過其名稱訪問它的值了:
fastify.utility()
console.log(fastify.conf.db)
decorateReply 顧名思義,decorateReply API允許你向 Reply 核心對(duì)象添加新方法。同 decorate 一樣,將新屬性與其值作為參數(shù)傳遞便大功告成了:
fastify.decorateReply('utility', function () {
// 新功能的代碼
})
注:使用箭頭函數(shù)會(huì)破壞 this 和 Fastify Reply 實(shí)例的綁定。
decorateRequest 同理,使用 decorateRequest 可向 Request 核心對(duì)象新增方法。傳遞的參數(shù)同樣也是新屬性的名稱以及值:
fastify.decorateRequest('utility', function () {
// 新功能的代碼
})
注:使用箭頭函數(shù)會(huì)破壞 this 和 Fastify Request 實(shí)例的綁定。
在經(jīng)過封裝的同一個(gè)插件中,如果通過 decorate、decorateRequest 以及 decorateReply 多次定義了一個(gè)同名的的裝飾器,F(xiàn)astify 將會(huì)拋出一個(gè)異常。
下面的示例會(huì)拋出異常:
const server = require('fastify')()
server.decorateReply('view', function (template, args) {
// 頁(yè)面渲染引擎的代碼。
})
server.get('/', (req, reply) => {
reply.view('/index.html', { hello: 'world' })
})
// 當(dāng)在其他地方定義
// view 裝飾器時(shí),拋出異常。
server.decorateReply('view', function (template, args) {
// 另一個(gè)渲染引擎。
})
server.listen(3000)
但下面這個(gè)例子不會(huì)拋異常:
const server = require('fastify')()
server.decorateReply('view', function (template, args) {
// 頁(yè)面渲染引擎的代碼。
})
server.register(async function (server, opts) {
// 我們?cè)诋?dāng)前封裝的插件內(nèi)添加了一個(gè) view 裝飾器。
// 這么做不會(huì)拋出異常。
// 因?yàn)椴寮獠亢蛢?nèi)部的 view 裝飾器是不一樣的。
server.decorateReply('view', function (template, args) {
// another rendering engine
})
server.get('/', (req, reply) => {
reply.view('/index.page', { hello: 'world' })
})
}, { prefix: '/bar' })
server.listen(3000)
裝飾器接受特別的 "getter/setter" 對(duì)象。這些對(duì)象擁有著名為 getter 與 setter 的函數(shù) (盡管 setter 是可選的)。這么做便可以通過裝飾器來定義屬性。例如:
fastify.decorate('foo', {
getter () {
return 'a getter'
}
})
上例會(huì)在 Fastify 實(shí)例中定義一個(gè) foo 屬性:
console.log(fastify.foo) // 'a getter'
decorateReply 與 decorateRequest 是分別用于向 Reply 和 Request 對(duì)象新增方法或?qū)傩缘摹D憧梢酝ㄟ^對(duì)象直接訪問這些屬性來更新它們。
讓我們向 Request 對(duì)象添加一個(gè)用戶屬性:
// 添加一個(gè) 'user' 請(qǐng)求裝飾器
fastify.decorateRequest('user', '')
// 更新屬性
fastify.addHook('preHandler', (req, reply, done) => {
req.user = 'Bob Dylan'
done()
})
// 最后,訪問裝飾器
fastify.get('/', (req, reply) => {
reply.send(`Hello ${req.user}!`)
})
注:在這個(gè)例子里,使用 decorateReply 或 decorateRequest 不是必要的,但這么做能提升 Fastify 的性能。
decorate 是 同步 的 API。如果你需要添加一個(gè) 異步 引導(dǎo)的裝飾器,F(xiàn)astify 可能會(huì)在該裝飾器準(zhǔn)備妥當(dāng)前啟動(dòng)。為了避免這種情況,你應(yīng)該將 register 與 fastify-plugin 一起使用。更多內(nèi)容,請(qǐng)看插件一文。
如果你的裝飾器依賴于其他裝飾器,你可以輕易地將其他裝飾器聲明為依賴項(xiàng)。你要做的只是將一個(gè)字符串?dāng)?shù)組 (表示依賴項(xiàng)的名稱) 作為函數(shù)的第三個(gè)參數(shù)而已:
fastify.decorate('utility', fn, ['greet', 'log'])
如果依賴關(guān)系不滿足,decorate 會(huì)拋出異常。但請(qǐng)別擔(dān)心:依賴檢查是在服務(wù)器啟動(dòng)之前執(zhí)行的,因此,在運(yùn)行時(shí)不會(huì)發(fā)生該問題。
使用 hasDecorator API 檢查一個(gè)裝飾器是否存在:
fastify.hasDecorator('utility')
使用 hasRequestDecorator API 檢查一個(gè)請(qǐng)求的的裝飾器是否存在:
fastify.hasRequestDecorator('utility')
使用 hasReplyDecorator API 檢查一個(gè)回復(fù)的裝飾器是否存在:
fastify.hasReplyDecorator('utility')
更多建議: