Skip to main content

插件

插件

¥Plugins

Fastify 允许用户通过插件扩展其功能。插件可以是一组路由、服务器 decorator 或其他任何东西。你需要使用一个或多个插件的 API 是 register

¥Fastify allows the user to extend its functionalities with plugins. A plugin can be a set of routes, a server decorator, or whatever. The API that you will need to use one or more plugins, is register.

默认情况下,register 会创建一个新范围,这意味着如果你对 Fastify 实例进行一些更改(通过 decorate),此更改将不会反映在当前上下文祖级中,而只会反映在其后代中。这个特性允许我们实现插件的封装和继承,这样我们就创建了一个有向无环图(DAG),并且不会出现交叉依赖带来的问题。

¥By default, register creates a new scope, this means that if you make some changes to the Fastify instance (via decorate), this change will not be reflected by the current context ancestors, but only by its descendants. This feature allows us to achieve plugin encapsulation and inheritance, in this way we create a directed acyclic graph (DAG) and we will not have issues caused by cross dependencies.

你可能已经在 入门 指南中看到了使用此 API 是多么容易:

¥You may have already seen in the Getting Started guide how easy it is to use 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 一起使用时,这些选项将被忽略

¥Note: Those options will be ignored when used with fastify-plugin

Fastify 将来可能会直接支持其他选项。因此,为了避免冲突,插件应该考虑为其选项命名空间。例如,插件 foo 可能像这样注册:

¥It is possible that Fastify will directly support other options in the future. Thus, 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 simply 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 that will be evaluated at the time the plugin is registered while giving access to the Fastify instance via the first positional 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 on 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 in case a plugin depends on changes made to the Fastify instance by a preceding plugin i.e. utilizing an existing database connection to wrap around it.

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

¥Keep in mind that the Fastify instance passed on to the function is the same as the one that will be 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 plugins function i.e. if decorate is called, the decorated variables will be available within the plugins function unless it was wrapped with fastify-plugin.

路由前缀选项

¥Route Prefixing option

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

¥If you pass an option with the key prefix with a string value, Fastify will use it to prefix all the routes inside the register, for more info check here.

请注意,如果你用 fastify-plugin 封装你的路由,此选项将不起作用(有 workaround 可用)。

¥Be aware that if you wrap your routes with fastify-plugin, this option will not work (there is a workaround available).

错误处理

¥Error handling

错误处理由 avvio 完成。

¥The error handling is done by avvio.

作为一般规则,强烈建议你在下一个 afterready 块中处理错误,否则你将在 listen 回调中收到它们。

¥As a general rule, it is highly recommended that you handle your errors in the next after or ready block, otherwise you will get them 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" 则进行封装过程。加载插件及其依赖后对插件的任何更改都不会反映在父实例中。

¥Note: Using await when registering a plugin loads the plugin and the underlying dependency tree, "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

Node.js v13.3.0 及以上版本也支持 ESM!

¥ESM is supported as well 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 very easy, you just need to 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

¥You can also use register inside another register:

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

fastify.get('/', handler)

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

done()
}

有时,你需要知道服务器何时即将关闭,例如,因为你必须关闭与数据库的连接。要知道何时会发生这种情况,你可以使用 'onClose' 钩子。

¥Sometimes, you will need to know when the server is about to close, for example, because you must close a connection to a database. To know when this is going to happen, you can use the 'onClose' hook.

不要忘记 register 总是会创建一个新的 Fastify 作用域,如果你不需要,请阅读以下部分。

¥Do not forget that register will always create a new Fastify scope, if you do not need that, read the following section.

处理范围

¥Handle the scope

如果你仅使用 register 来使用 decorate 扩展服务器的功能,则你有责任告诉 Fastify 不要创建新的范围。否则,上层范围内的用户将无法访问你的更改。

¥If you are using register only for extending the functionality of the server with decorate, it is your responsibility to tell Fastify not to create a new scope. Otherwise, your changes will not be accessible by the user in the upper scope.

你有两种方法告诉 Fastify 避免创建新上下文:

¥You have two ways to tell Fastify to avoid the creation of a new context:

我们建议使用 fastify-plugin 模块,因为它为你解决了这个问题,并且你可以将 Fastify 的版本范围作为你的插件将支持的参数传递。

¥We recommend using the fastify-plugin module, because it solves this problem for you, and you can pass a version range of Fastify as a parameter that your 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' hidden 属性,但我们不建议这样做。如果将来 Fastify API 发生变化,你将有责任更新模块,而如果你使用 fastify-plugin,则可以确保向后兼容。

¥If you do not use the fastify-plugin module, you can use the 'skip-override' hidden property, but we do not recommend it. If in the future the Fastify API changes it will be your responsibility to update the module, while if you use fastify-plugin, you can be sure about backward compatibility.

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