Skip to main content

插件

插件

¥Plugins

Fastify 可以通过插件进行扩展,插件可以是一组路由、服务器 decorator 或其他功能。使用 register API 添加一个或多个插件。

¥Fastify can be extended with plugins, which can be a set of routes, a server decorator, or other functionality. Use the register API to add one or more plugins.

默认情况下,register 会创建一个新范围,这意味着对 Fastify 实例的更改(通过 decorate)不会影响当前上下文祖级,只会影响其后代。此功能支持插件封装和继承,创建有向无环图 (DAG) 并避免交叉依赖问题。

¥By default, register creates a new scope, meaning changes to the Fastify instance (via decorate) will not affect the current context ancestors, only its descendants. This feature enables plugin encapsulation and inheritance, creating a directed acyclic graph (DAG) and avoiding cross-dependency issues.

入门 指南包含使用此 API 的示例:

¥The Getting Started guide includes an example of using this API:

fastify.register(plugin, [options])

插件选项

¥Plugin Options

fastify.register 的可选 options 参数支持一组预定义的选项,Fastify 本身将使用这些选项,除非插件已用 fastify-plugin 封装。无论插件是否已封装,此选项对象也将在调用时传递给插件。当前支持的 Fastify 特定选项列表是:

¥The optional options parameter for fastify.register supports a predefined set of options that Fastify itself will use, except when the plugin has been wrapped with fastify-plugin. This options object will also be passed to the plugin upon invocation, regardless of whether or not the plugin has been wrapped. The currently supported list of Fastify specific options is:

与 fastify-plugin 一起使用时,这些选项将被忽略。

¥These options will be ignored when used with fastify-plugin.

为避免冲突,插件应考虑命名空间其选项。例如,插件 foo 可能像这样注册:

¥To avoid collisions, a plugin should consider namespacing its options. For example, a plugin foo might be registered like so:

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

如果不担心冲突,插件可以按原样接受选项对象:

¥If collisions are not a concern, the plugin may accept the options object as-is:

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

options 参数也可以是在插件注册时评估的 Function,通过第一个参数提供对 Fastify 实例的访问:

¥The options parameter can also be a Function evaluated at plugin registration, providing access to the Fastify instance via the first argument:

const fp = require('fastify-plugin')

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

done()
}))

// The opts argument of fastify-foo will be { hello: 'world' }
fastify.register(require('fastify-foo'), parent => parent.foo_bar)

传递给函数的 Fastify 实例是声明插件的外部 Fastify 实例的最新状态,允许根据注册顺序访问通过 decorate 由前面的插件注入的变量。如果插件依赖于前一个插件对 Fastify 实例所做的更改(例如利用现有的数据库连接),这将很有用。

¥The Fastify instance passed to the function is the latest state of the external Fastify instance the plugin was declared on, allowing access to variables injected via decorate by preceding plugins according to the order of registration. This is useful if a plugin depends on changes made to the Fastify instance by a preceding plugin, such as utilizing an existing database connection.

请记住,传递给函数的 Fastify 实例与传递给插件的实例相同,是外部 Fastify 实例的副本而不是引用。实例的任何使用都将表现得与在插件函数内调用时相同。例如,如果调用 decorate,则除非使用 fastify-plugin 封装,否则修饰变量将在插件函数中可用。

¥Keep in mind that the Fastify instance passed to the function is the same as the one passed into the plugin, a copy of the external Fastify instance rather than a reference. Any usage of the instance will behave the same as it would if called within the plugin's function. For example, if decorate is called, the decorated variables will be available within the plugin's function unless it was wrapped with fastify-plugin.

路由前缀选项

¥Route Prefixing option

如果传递了带有键 prefixstring 值的选项,Fastify 将使用它作为注册内所有路由的前缀。有关更多信息,请查看 此处

¥If an option with the key prefix and a string value is passed, Fastify will use it to prefix all the routes inside the register. For more info, check here.

请注意,如果路由用 fastify-plugin 封装,则此选项将不起作用(请参阅 workaround)。

¥Be aware that if routes are wrapped with fastify-plugin, this option will not work (see the workaround).

错误处理

¥Error handling

错误处理由 avvio 完成。

¥Error handling is done by avvio.

作为一般规则,在下一个 afterready 块中处理错误,否则它们将被捕获在 listen 回调中。

¥As a general rule, handle errors in the next after or ready block, otherwise they will be caught inside the listen callback.

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

// `after` will be executed once
// the previous declared `register` has finished
fastify.after(err => console.log(err))

// `ready` will be executed once all the registers declared
// have finished their execution
fastify.ready(err => console.log(err))

// `listen` is a special ready,
// so it behaves in the same way
fastify.listen({ port: 3000 }, (err, address) => {
if (err) console.log(err)
})

async/await

afterreadylisten 支持 async/await,fastify 也是 Thenable。

¥async/await is supported by after, ready, and listen, as well as fastify being a Thenable.

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

await fastify.after()

await fastify.ready()

await fastify.listen({ port: 3000 })

注册插件时使用 await 会加载插件及其依赖,"finalizing" 是封装过程。加载插件及其依赖后对插件的任何更改都不会反映在父实例中。

¥Using await when registering a plugin loads the plugin and its dependencies, "finalizing" the encapsulation process. Any mutations to the plugin after it and its dependencies have been loaded will not be reflected in the parent instance.

无害化管理支持

¥ESM support

ESM 从 Node.js v13.3.0 及以上版本开始受支持。

¥ESM is supported from Node.js v13.3.0 and above.

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

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

fastify.listen({ port: 3000 }, console.log)


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

export default plugin

创建一个插件

¥Create a plugin

创建插件很容易。创建一个接受三个参数的函数:fastify 实例、options 对象和 done 回调。

¥Creating a plugin is easy. Create a function that takes three parameters: the fastify instance, an options object, and the done callback.

示例:

¥Example:

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

fastify.get('/', handler)

done()
}

register 也可以在另一个 register 中使用:

¥register can also be used inside another register:

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

fastify.get('/', handler)

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

done()
}

请记住,register 始终会创建一个新的 Fastify 范围。如果不需要,请阅读以下部分。

¥Remember, register always creates a new Fastify scope. If this is not needed, read the following section.

处理范围

¥Handle the scope

如果 register 仅用于通过 decorate 扩展服务器功能,请告诉 Fastify 不要创建新的作用域。否则,更改将无法在上层范围内访问。

¥If register is used only to extend server functionality with decorate, tell Fastify not to create a new scope. Otherwise, changes will not be accessible in the upper scope.

有两种方法可以避免创建新上下文:

¥There are two ways to avoid creating a new context:

  • 使用 fastify-plugin 模块

    ¥Use the fastify-plugin module

  • 使用 'skip-override' 隐藏属性

    ¥Use the 'skip-override' hidden property

建议使用 fastify-plugin 模块,因为它解决了这个问题并允许传递插件将支持的 Fastify 版本范围:

¥Using the fastify-plugin module is recommended, as it solves this problem and allows passing a version range of Fastify that the plugin will support:

const fp = require('fastify-plugin')

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

查看 fastify-plugin 文档以了解有关如何使用此模块的更多信息。

¥Check the fastify-plugin documentation to learn more about how to use this module.

如果不使用 fastify-plugin,可以使用 'skip-override' 隐藏属性,但不建议这样做。未来的 Fastify API 更改将由你负责更新,而 fastify-plugin 确保向后兼容。

¥If not using fastify-plugin, the 'skip-override' hidden property can be used, but it is not recommended. Future Fastify API changes will be your responsibility to update, whilst fastify-plugin ensures backward compatibility.

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