封裝
封裝
Fastify 的一個基本特性是「封裝上下文」。封裝上下文控制哪些裝飾器、已註冊的鉤子和外掛可供路由使用。封裝上下文的可視化表示如下圖所示
在上圖中,有幾個實體
- 根上下文
- 三個根外掛
- 兩個子上下文,其中每個子上下文都有
- 兩個子外掛
- 一個孫上下文,其中每個孫上下文都有
- 三個子外掛
每個子上下文和孫上下文都可以存取根外掛。在每個子上下文中,孫上下文可以存取在包含的子上下文中註冊的子外掛,但包含的子上下文無法存取在其孫上下文中註冊的子外掛。
鑒於 Fastify 中的所有內容(除了根上下文)都是一個外掛,因此本例中的每個「上下文」和「外掛」都是一個外掛,其中可以包含裝飾器、鉤子、外掛和路由。因此,為了將這個例子具體化,請考慮一個具有三個路由的 REST API 伺服器的基本場景:第一個路由 (/one
) 需要身份驗證,第二個路由 (/two
) 不需要,第三個路由 (/three
) 可以存取與第二個路由相同的上下文。使用@fastify/bearer-auth 提供身份驗證,此範例的程式碼如下
'use strict'
const fastify = require('fastify')()
fastify.decorateRequest('answer', 42)
fastify.register(async function authenticatedContext (childServer) {
childServer.register(require('@fastify/bearer-auth'), { keys: ['abc123'] })
childServer.route({
path: '/one',
method: 'GET',
handler (request, response) {
response.send({
answer: request.answer,
// request.foo will be undefined as it's only defined in publicContext
foo: request.foo,
// request.bar will be undefined as it's only defined in grandchildContext
bar: request.bar
})
}
})
})
fastify.register(async function publicContext (childServer) {
childServer.decorateRequest('foo', 'foo')
childServer.route({
path: '/two',
method: 'GET',
handler (request, response) {
response.send({
answer: request.answer,
foo: request.foo,
// request.bar will be undefined as it's only defined in grandchildContext
bar: request.bar
})
}
})
childServer.register(async function grandchildContext (grandchildServer) {
grandchildServer.decorateRequest('bar', 'bar')
grandchildServer.route({
path: '/three',
method: 'GET',
handler (request, response) {
response.send({
answer: request.answer,
foo: request.foo,
bar: request.bar
})
}
})
})
})
fastify.listen({ port: 8000 })
上面的伺服器範例展示了原始圖表中概述的所有封裝概念
- 每個子上下文 (
authenticatedContext
、publicContext
和grandchildContext
) 都可以存取在根上下文中定義的answer
請求裝飾器。 - 只有
authenticatedContext
可以存取@fastify/bearer-auth
外掛。 publicContext
和grandchildContext
都可以存取foo
請求裝飾器。- 只有
grandchildContext
可以存取bar
請求裝飾器。
要查看這一點,請啟動伺服器並發出請求
# curl -H 'authorization: Bearer abc123' http://127.0.0.1:8000/one
{"answer":42}
# curl http://127.0.0.1:8000/two
{"answer":42,"foo":"foo"}
# curl http://127.0.0.1:8000/three
{"answer":42,"foo":"foo","bar":"bar"}
上下文之間的共享
請注意,先前範例中的每個上下文都僅繼承自父上下文。父上下文無法存取其後代上下文中的任何實體。這種預設情況有時並非理想。在這種情況下,可以使用fastify-plugin來打破封裝上下文,以便在後代上下文中註冊的任何內容都可供包含的父上下文使用。
假設 publicContext
需要存取先前範例中在 grandchildContext
中定義的 bar
裝飾器,則程式碼可以重寫為
'use strict'
const fastify = require('fastify')()
const fastifyPlugin = require('fastify-plugin')
fastify.decorateRequest('answer', 42)
// `authenticatedContext` omitted for clarity
fastify.register(async function publicContext (childServer) {
childServer.decorateRequest('foo', 'foo')
childServer.route({
path: '/two',
method: 'GET',
handler (request, response) {
response.send({
answer: request.answer,
foo: request.foo,
bar: request.bar
})
}
})
childServer.register(fastifyPlugin(grandchildContext))
async function grandchildContext (grandchildServer) {
grandchildServer.decorateRequest('bar', 'bar')
grandchildServer.route({
path: '/three',
method: 'GET',
handler (request, response) {
response.send({
answer: request.answer,
foo: request.foo,
bar: request.bar
})
}
})
}
})
fastify.listen({ port: 8000 })
重新啟動伺服器並重新發出對 /two
和 /three
的請求
# curl http://127.0.0.1:8000/two
{"answer":42,"foo":"foo","bar":"bar"}
# curl http://127.0.0.1:8000/three
{"answer":42,"foo":"foo","bar":"bar"}