注册插件 #
一、注册方式 #
1.1 基本注册 #
使用 register 方法注册插件:
javascript
const fastify = require('fastify')()
fastify.register(require('@fastify/cors'))
fastify.listen({ port: 3000 })
1.2 带选项注册 #
javascript
fastify.register(require('@fastify/cors'), {
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE']
})
1.3 前缀注册 #
javascript
fastify.register(require('./routes/api'), {
prefix: '/api/v1'
})
1.4 异步注册 #
javascript
await fastify.register(require('@fastify/mongodb'), {
url: 'mongodb://localhost:27017/mydb'
})
console.log('MongoDB plugin registered')
二、自动加载 #
2.1 使用@fastify/autoload #
javascript
const fastify = require('fastify')()
const path = require('path')
fastify.register(require('@fastify/autoload'), {
dir: path.join(__dirname, 'plugins')
})
fastify.register(require('@fastify/autoload'), {
dir: path.join(__dirname, 'routes')
})
2.2 目录结构 #
text
app/
├── plugins/
│ ├── database.js
│ ├── auth.js
│ └── cache.js
├── routes/
│ ├── users.js
│ └── products.js
└── app.js
2.3 自动加载选项 #
javascript
fastify.register(require('@fastify/autoload'), {
dir: path.join(__dirname, 'plugins'),
ignorePattern: /.*\.test\.js$/,
dirNameRoutePrefix: (folderName) => {
return folderName === 'api' ? '' : folderName
},
options: {
database: { url: process.env.DB_URL }
}
})
2.4 嵌套目录 #
text
routes/
├── api/
│ ├── v1/
│ │ ├── users.js → /api/v1/users
│ │ └── products.js → /api/v1/products
│ └── v2/
│ └── users.js → /api/v2/users
└── web/
└── pages.js → /web/pages
三、核心插件 #
3.1 @fastify/cors #
跨域资源共享:
javascript
fastify.register(require('@fastify/cors'), {
origin: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400
})
自定义配置:
javascript
fastify.register(require('@fastify/cors'), {
origin: (origin, cb) => {
const allowedOrigins = ['https://example.com', 'https://api.example.com']
if (!origin || allowedOrigins.includes(origin)) {
cb(null, true)
} else {
cb(new Error('Not allowed'), false)
}
}
})
3.2 @fastify/helmet #
安全头设置:
javascript
fastify.register(require('@fastify/helmet'), {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
})
3.3 @fastify/jwt #
JWT认证:
javascript
fastify.register(require('@fastify/jwt'), {
secret: process.env.JWT_SECRET,
sign: {
expiresIn: '7d'
}
})
fastify.post('/login', async (request, reply) => {
const token = fastify.jwt.sign({ userId: 1 })
return { token }
})
fastify.get('/protected', {
preHandler: async (request, reply) => {
await request.jwtVerify()
}
}, async (request, reply) => {
return { user: request.user }
})
3.4 @fastify/cookie #
Cookie处理:
javascript
fastify.register(require('@fastify/cookie'), {
secret: 'my-secret-key',
parseOptions: {
httpOnly: true,
secure: true,
sameSite: 'strict'
}
})
fastify.get('/set-cookie', async (request, reply) => {
reply.setCookie('sessionId', 'abc123', {
httpOnly: true,
secure: true,
maxAge: 3600
})
return { message: 'Cookie set' }
})
fastify.get('/get-cookie', async (request, reply) => {
return { sessionId: request.cookies.sessionId }
})
3.5 @fastify/static #
静态文件服务:
javascript
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
prefix: '/static/',
maxAge: 31536000,
decorateReply: true
})
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'uploads'),
prefix: '/uploads/',
decorateReply: false
})
3.6 @fastify/multipart #
文件上传:
javascript
fastify.register(require('@fastify/multipart'), {
limits: {
fileSize: 10 * 1024 * 1024,
files: 5
}
})
fastify.post('/upload', async (request, reply) => {
const data = await request.file()
const buffer = await data.toBuffer()
return {
filename: data.filename,
mimetype: data.mimetype,
size: buffer.length
}
})
3.7 @fastify/rate-limit #
请求限流:
javascript
fastify.register(require('@fastify/rate-limit'), {
max: 100,
timeWindow: '1 minute',
keyGenerator: (request) => {
return request.ip
}
})
fastify.get('/limited', {
config: {
rateLimit: {
max: 10,
timeWindow: '1 minute'
}
}
}, async (request, reply) => {
return { message: 'Rate limited route' }
})
3.8 @fastify/swagger #
API文档:
javascript
fastify.register(require('@fastify/swagger'), {
openapi: {
openapi: '3.0.0',
info: {
title: 'My API',
description: 'API documentation',
version: '1.0.0'
},
servers: [
{ url: 'http://localhost:3000' }
]
}
})
fastify.register(require('@fastify/swagger-ui'), {
routePrefix: '/documentation',
uiConfig: {
docExpansion: 'list'
}
})
fastify.get('/users', {
schema: {
description: 'Get all users',
tags: ['Users'],
response: {
200: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'integer' },
name: { type: 'string' }
}
}
}
}
}
}, async (request, reply) => {
return [{ id: 1, name: 'John' }]
})
四、数据库插件 #
4.1 MongoDB #
javascript
fastify.register(require('@fastify/mongodb'), {
url: 'mongodb://localhost:27017/mydb',
database: 'mydb'
})
fastify.get('/users', async (request, reply) => {
const users = await fastify.mongo.db.collection('users').find({}).toArray()
return users
})
4.2 PostgreSQL #
javascript
fastify.register(require('@fastify/postgres'), {
connectionString: 'postgresql://user:pass@localhost:5432/mydb'
})
fastify.get('/users', async (request, reply) => {
const result = await fastify.pg.query('SELECT * FROM users')
return result.rows
})
4.3 Redis #
javascript
fastify.register(require('@fastify/redis'), {
host: 'localhost',
port: 6379
})
fastify.get('/cache', async (request, reply) => {
const cached = await fastify.redis.get('key')
if (cached) {
return JSON.parse(cached)
}
const data = { message: 'Hello' }
await fastify.redis.set('key', JSON.stringify(data), 'EX', 3600)
return data
})
五、会话插件 #
5.1 @fastify/session #
javascript
fastify.register(require('@fastify/cookie'))
fastify.register(require('@fastify/session'), {
secret: 'a-very-long-secret-key-here',
cookie: {
secure: false,
maxAge: 3600000
},
saveUninitialized: false
})
fastify.post('/login', async (request, reply) => {
request.session.userId = 1
return { message: 'Logged in' }
})
fastify.get('/profile', async (request, reply) => {
if (!request.session.userId) {
reply.code(401).send({ error: 'Not logged in' })
return
}
return { userId: request.session.userId }
})
fastify.post('/logout', async (request, reply) => {
request.session.destroy()
return { message: 'Logged out' }
})
5.2 @fastify/secure-session #
javascript
fastify.register(require('@fastify/secure-session'), {
secret: 'a-very-long-secret-key-here',
salt: 'salt-value'
})
fastify.post('/login', async (request, reply) => {
request.session.set('userId', 1)
return { message: 'Logged in' }
})
fastify.get('/profile', async (request, reply) => {
const userId = request.session.get('userId')
if (!userId) {
reply.code(401).send({ error: 'Not logged in' })
return
}
return { userId }
})
六、表单插件 #
6.1 @fastify/formbody #
javascript
fastify.register(require('@fastify/formbody'))
fastify.post('/form', async (request, reply) => {
return { body: request.body }
})
6.2 表单验证 #
javascript
fastify.post('/login', {
schema: {
body: {
type: 'object',
required: ['username', 'password'],
properties: {
username: { type: 'string' },
password: { type: 'string', minLength: 6 }
}
}
}
}, async (request, reply) => {
const { username, password } = request.body
return { username }
})
七、视图插件 #
7.1 @fastify/view #
javascript
fastify.register(require('@fastify/view'), {
engine: {
ejs: require('ejs')
},
root: path.join(__dirname, 'views'),
layout: 'layout.ejs'
})
fastify.get('/page', async (request, reply) => {
return reply.view('index.ejs', { title: 'Hello', message: 'World' })
})
7.2 多模板引擎 #
javascript
fastify.register(require('@fastify/view'), {
engine: {
ejs: require('ejs'),
pug: require('pug'),
handlebars: require('handlebars')
},
root: path.join(__dirname, 'views')
})
fastify.get('/ejs', async (request, reply) => {
return reply.view('index.ejs', { title: 'EJS' })
})
fastify.get('/pug', async (request, reply) => {
return reply.view('index.pug', { title: 'Pug' })
})
八、压缩插件 #
8.1 @fastify/compress #
javascript
fastify.register(require('@fastify/compress'), {
global: true,
threshold: 1024,
encodings: ['gzip', 'deflate', 'br']
})
fastify.get('/large-data', async (request, reply) => {
return { data: 'Large response data...' }
})
九、健康检查插件 #
9.1 @fastify/under-pressure #
javascript
fastify.register(require('@fastify/under-pressure'), {
maxEventLoopDelay: 1000,
maxHeapUsedBytes: 100000000,
maxRssBytes: 100000000,
message: 'Server under pressure',
retryAfter: 50
})
fastify.get('/health', async (request, reply) => {
return fastify.memoryUsage()
})
十、插件注册最佳实践 #
10.1 注册顺序 #
javascript
const fastify = require('fastify')()
fastify.register(require('@fastify/sensible'))
fastify.register(require('@fastify/cors'))
fastify.register(require('@fastify/helmet'))
fastify.register(require('./plugins/database'))
fastify.register(require('./plugins/redis'))
fastify.register(require('./plugins/auth'))
fastify.register(require('./routes'))
fastify.listen({ port: 3000 })
10.2 环境区分 #
javascript
if (process.env.NODE_ENV === 'development') {
fastify.register(require('@fastify/swagger'))
fastify.register(require('@fastify/swagger-ui'))
}
if (process.env.NODE_ENV === 'production') {
fastify.register(require('@fastify/compress'))
}
10.3 错误处理 #
javascript
fastify.register(require('@fastify/mongodb'), {
url: process.env.MONGODB_URL
}).after(err => {
if (err) {
fastify.log.error('MongoDB connection failed:', err)
throw err
}
fastify.log.info('MongoDB connected')
})
十一、总结 #
本章我们学习了:
- 注册方式:基本注册、带选项注册、前缀注册
- 自动加载:@fastify/autoload的使用
- 核心插件:cors、helmet、jwt、cookie、static等
- 数据库插件:MongoDB、PostgreSQL、Redis
- 会话插件:session、secure-session
- 表单插件:formbody
- 视图插件:view
- 压缩插件:compress
- 健康检查:under-pressure
- 最佳实践:注册顺序、环境区分、错误处理
接下来让我们学习如何编写自定义插件!
最后更新:2026-03-28