Fastify 插件

2020-02-06 15:42 更新

插件

Fastify 允許用戶通過插件的方式擴展自身的功能。 一個插件可以是一組路由,一個服務(wù)器裝飾器或者其他任意的東西。 在使用一個或者許多插件時,只需要一個 API register。

默認, register 會創(chuàng)建一個 新的作用域( Scope ), 這意味著你能夠改變 Fastify 實例(通過decorate), 這個改變不會反映到當前作用域, 只會影響到子作用域。 這樣可以做到插件的封裝和繼承, 我們創(chuàng)建了一個無回路有向圖(DAG), 因此不會有交叉依賴的問題。

你已經(jīng)在起步部分很直觀的看到了怎么使用這個 API。

fastify.register(plugin, [options])

插件選項

fastify.register 可選參數(shù)列表支持一組預(yù)定義的 Fastify 可用的參數(shù), 除了當插件使用了 fastify-plugin。 選項對象會在插件被調(diào)用傳遞進去, 無論這個插件是否用了 fastify-plugin。 當前支持的選項有:

注意:當使用 fastify-plugin 時,這些選項會被忽略

Fastify 有可能在將來會直接支持其他的選項。 因此為了避免沖突, 插件應(yīng)該考慮給選項加入命名空間。 舉個例子, 插件 foo 可以像以下代碼一樣注冊:

fastify.register(require('fastify-foo'), {
  prefix: '/foo',
  foo: {
    fooOption1: 'value',
    fooOption2: 'value'
  }
})

如果不考慮沖突, 插件可以簡化成直接接收對象參數(shù):

fastify.register(require('fastify-foo'), {
  prefix: '/foo',
  fooOption1: 'value',
  fooOption2: 'value'
})

options 參數(shù)還可以是一個在插件注冊時確定的 函數(shù),這個函數(shù)的第一位參數(shù)是 fastify 實例:

const fp = require('fastify-plugin')

fastify.register(fp((fastify, opts, done) => {
  fastify.decorate('foo_bar', { hello: 'world' })

  done()
}))

// fastify-foo 的 options 參數(shù)會是 { hello: 'world' }
fastify.register(require('fastify-foo'), parent => parent.foo_bar)

傳給函數(shù)的 fastify 實例是插件聲明時外部 fastify 實例的最新狀態(tài),允許你訪問注冊順序在前的插件通過 decorate 注入的變量。這在需要依賴前置插件對于 Fastify 實例的改動時派得上用場,比如,使用已存在的數(shù)據(jù)庫連接來包裝你的插件。

請記住,傳給函數(shù)的 fastify 實例和傳給插件的實例是一樣的,不是外部 fastify 實例的引用,而是拷貝。任何對函數(shù)的實例參數(shù)的操作結(jié)果,都會和在插件函數(shù)中操作的結(jié)果一致。也就是說,如果調(diào)用了 decorate,被注入的變量在插件函數(shù)中也是可用的,除非你使用 fastify-plugin 包裝了這個插件。

路由前綴選項

如果你傳入以 prefix為 key , string 為值的選項, Fastify 會自動為這個插件下所有的路由添加這個前綴, 更多信息可以查詢 這里.注意如果使用了 fastify-plugin 這個選項不會起作用。

錯誤處理

錯誤處理是由 avvio 解決的。一個通用的原則, 我們建議在下一個 after 或 ready 代碼塊中處理錯誤, 否則錯誤將出現(xiàn)在 listen 回調(diào)里。

fastify.register(require('my-plugin'))

// `after` 將在上一個 `register` 結(jié)束后執(zhí)行
fastify.after(err => console.log(err))

// `ready` 將在所有 `register` 結(jié)束后執(zhí)行
fastify.ready(err => console.log(err))

// `listen` 是一個特殊的 `ready`,
// 因此它的執(zhí)行時機與 `ready` 一致
fastify.listen(3000, (err, address) => {
  if (err) console.log(err)
})

async-await 只被 ready 與 listen 支持。

fastify.register(require('my-plugin'))

await fastify.ready()

await fastify.listen(3000)

ESM 的支持

自 Node.js v13.3.0 開始, ESM 也被支持了!

// main.mjs
import Fastify from 'fastify'
const fastify = Fastify()

fastify.register(import('./plugin.mjs'))

fastify.listen(3000, console.log)

// plugin.mjs
async function plugin (fastify, opts) {
  fastify.get('/', async (req, reply) => {
    return { hello: 'world' }
  })
}

export default plugin

創(chuàng)建插件

創(chuàng)建插件非常簡單, 你只需要創(chuàng)建一個方法, 這個方法接收三個參數(shù): fastify 實例、options 選項和 done 回調(diào)。例子:

module.exports = function (fastify, opts, done) {
  fastify.decorate('utility', () => {})

  fastify.get('/', handler)

  done()
}

你也可以在一個 register 內(nèi)部添加其他 register:

module.exports = function (fastify, opts, done) {
  fastify.decorate('utility', () => {})

  fastify.get('/', handler)

  fastify.register(require('./other-plugin'))

  done()
}

有時候, 你需要知道這個服務(wù)器何時即將關(guān)閉, 例如在你必須關(guān)閉數(shù)據(jù)庫連接的時候。 要知道什么時候發(fā)生這種情況, 你可以用 'onClose' 鉤子。

別忘了 register 會創(chuàng)建一個新的 Fastify 作用域, 如果你不需要, 閱讀下面的章節(jié)。

處理作用域

如果你使用 register 僅僅是為了通過decorate擴展服務(wù)器的功能, 你需要告訴 Fastify 不要創(chuàng)建新的上下文, 不然你的改動不會影響其他作用域中的用戶。

你有兩種方式告訴 Fastify 避免創(chuàng)建新的上下文:

  • 使用 fastify-plugin 模塊
  • 使用 'skip-override' 隱藏屬性

我們建議使用 fastify-plugin 模塊, 因為它是專門用來為你解決這個問題, 并且你可以傳一個能夠支持的 Fastify 版本范圍的參數(shù)。

const fp = require('fastify-plugin')

module.exports = fp(function (fastify, opts, done) {
  fastify.decorate('utility', () => {})
  done()
}, '0.x')

參考 fastify-plugin 文檔了解更多這個模塊。

如果你不用 fastify-plugin 模塊, 可以使用 'skip-override' 隱藏屬性, 但我們不推薦這么做。 如果將來 Fastify API 改變了, 你需要去更新你的模塊, 如果使用 fastify-plugin, 你可以對向后兼容放心。

function yourPlugin (fastify, opts, done) {
  fastify.decorate('utility', () => {})
  done()
}
yourPlugin[Symbol.for('skip-override')] = true
module.exports = yourPlugin


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號