常用中间件 #
一、安全中间件 #
1.1 @fastify/helmet #
安全头设置,保护应用免受常见Web漏洞。
安装:
bash
npm install @fastify/helmet
基本使用:
javascript
fastify.register(require('@fastify/helmet'))
自定义配置:
javascript
fastify.register(require('@fastify/helmet'), {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
xssFilter: true,
noSniff: true,
referrerPolicy: { policy: 'strict-origin-when-cross-origin' }
})
1.2 @fastify/cors #
跨域资源共享配置。
安装:
bash
npm install @fastify/cors
基本使用:
javascript
fastify.register(require('@fastify/cors'))
自定义配置:
javascript
fastify.register(require('@fastify/cors'), {
origin: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Total-Count'],
credentials: true,
maxAge: 86400
})
动态origin:
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 by CORS'), false)
}
}
})
正则匹配:
javascript
fastify.register(require('@fastify/cors'), {
origin: [/\.example\.com$/]
})
1.3 @fastify/rate-limit #
请求限流,防止滥用。
安装:
bash
npm install @fastify/rate-limit
基本使用:
javascript
fastify.register(require('@fastify/rate-limit'), {
max: 100,
timeWindow: '1 minute'
})
自定义配置:
javascript
fastify.register(require('@fastify/rate-limit'), {
max: 100,
timeWindow: '1 minute',
keyGenerator: (request) => {
return request.headers['x-api-key'] || request.ip
},
errorResponseBuilder: (request, context) => {
return {
statusCode: 429,
error: 'Too Many Requests',
message: `Rate limit exceeded, retry in ${context.after}`,
retryAfter: context.ttl
}
},
addHeaders: {
'x-ratelimit-limit': true,
'x-ratelimit-remaining': true,
'x-ratelimit-reset': true,
'retry-after': true
}
})
路由级限流:
javascript
fastify.get('/api/data', {
config: {
rateLimit: {
max: 10,
timeWindow: '1 minute'
}
}
}, async (request, reply) => {
return { data: [] }
})
Redis存储:
javascript
fastify.register(require('@fastify/rate-limit'), {
max: 100,
timeWindow: '1 minute',
redis: {
host: 'localhost',
port: 6379
}
})
二、认证中间件 #
2.1 @fastify/jwt #
JWT认证。
安装:
bash
npm install @fastify/jwt
基本使用:
javascript
fastify.register(require('@fastify/jwt'), {
secret: 'supersecret'
})
fastify.post('/login', async (request, reply) => {
const token = fastify.jwt.sign({ userId: 1, role: 'user' })
return { token }
})
fastify.get('/protected', {
preHandler: async (request, reply) => {
await request.jwtVerify()
}
}, async (request, reply) => {
return { user: request.user }
})
自定义配置:
javascript
fastify.register(require('@fastify/jwt'), {
secret: {
private: privateKey,
public: publicKey
},
sign: {
algorithm: 'RS256',
expiresIn: '7d'
},
verify: {
algorithms: ['RS256']
}
})
装饰器使用:
javascript
fastify.register(require('@fastify/jwt'), {
secret: 'secret'
})
fastify.decorate('authenticate', async function (request, reply) {
try {
await request.jwtVerify()
} catch (err) {
reply.code(401).send({ error: 'Unauthorized' })
}
})
fastify.get('/profile', {
preHandler: fastify.authenticate
}, async (request, reply) => {
return { user: request.user }
})
2.2 @fastify/cookie #
Cookie处理。
安装:
bash
npm install @fastify/cookie
基本使用:
javascript
fastify.register(require('@fastify/cookie'))
fastify.get('/set-cookie', async (request, reply) => {
reply.setCookie('sessionId', 'abc123', {
httpOnly: true,
secure: true,
sameSite: 'strict'
})
return { message: 'Cookie set' }
})
fastify.get('/get-cookie', async (request, reply) => {
return { sessionId: request.cookies.sessionId }
})
签名Cookie:
javascript
fastify.register(require('@fastify/cookie'), {
secret: 'my-secret-key',
parseOptions: {
httpOnly: true,
secure: true,
sameSite: 'strict'
}
})
fastify.get('/signed', async (request, reply) => {
reply.setCookie('data', 'value', { signed: true })
return { message: 'Signed cookie set' }
})
fastify.get('/verify', async (request, reply) => {
const data = request.unsignCookie(request.cookies.data)
return { valid: data.valid, value: data.value }
})
2.3 @fastify/session #
会话管理。
安装:
bash
npm install @fastify/session @fastify/cookie
基本使用:
javascript
fastify.register(require('@fastify/cookie'))
fastify.register(require('@fastify/session'), {
secret: 'a-very-long-secret-key-here',
cookie: {
secure: 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' }
})
三、数据中间件 #
3.1 @fastify/multipart #
文件上传。
安装:
bash
npm install @fastify/multipart
基本使用:
javascript
fastify.register(require('@fastify/multipart'))
fastify.post('/upload', async (request, reply) => {
const data = await request.file()
return {
filename: data.filename,
mimetype: data.mimetype,
encoding: data.encoding
}
})
保存文件:
javascript
const fs = require('fs')
const path = require('path')
fastify.post('/upload', async (request, reply) => {
const data = await request.file()
const uploadPath = path.join(__dirname, 'uploads', data.filename)
await fs.promises.mkdir(path.dirname(uploadPath), { recursive: true })
await data.file.pipe(fs.createWriteStream(uploadPath))
return { filename: data.filename }
})
多文件上传:
javascript
fastify.post('/uploads', async (request, reply) => {
const files = []
for await (const part of request.parts()) {
if (part.type === 'file') {
files.push({
filename: part.filename,
mimetype: part.mimetype
})
}
}
return { files }
})
限制配置:
javascript
fastify.register(require('@fastify/multipart'), {
limits: {
fileSize: 10 * 1024 * 1024,
files: 5,
fields: 10,
fieldNameSize: 100,
fieldSize: 1024 * 1024
}
})
3.2 @fastify/static #
静态文件服务。
安装:
bash
npm install @fastify/static
基本使用:
javascript
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
prefix: '/static/'
})
多目录:
javascript
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
prefix: '/public/',
decorateReply: false
})
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'uploads'),
prefix: '/uploads/',
decorateReply: false
})
配置选项:
javascript
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
prefix: '/static/',
maxAge: 31536000,
cacheControl: true,
lastModified: true,
etag: true,
index: 'index.html',
serve: true,
decorateReply: true
})
四、压缩中间件 #
4.1 @fastify/compress #
响应压缩。
安装:
bash
npm install @fastify/compress
基本使用:
javascript
fastify.register(require('@fastify/compress'))
自定义配置:
javascript
fastify.register(require('@fastify/compress'), {
global: true,
threshold: 1024,
encodings: ['gzip', 'deflate', 'br'],
gzip: {
flush: require('zlib').constants.Z_SYNC_FLUSH
},
deflate: {
flush: require('zlib').constants.Z_SYNC_FLUSH
},
brotli: {
flush: require('zlib').constants.BROTLI_OPERATION_FLUSH
}
})
路由级压缩:
javascript
fastify.get('/large-data', {
compress: {
type: 'gzip',
threshold: 1024
}
}, async (request, reply) => {
return { data: 'Large response...' }
})
五、API文档中间件 #
5.1 @fastify/swagger #
OpenAPI文档生成。
安装:
bash
npm install @fastify/swagger @fastify/swagger-ui
基本配置:
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',
deepLinking: true
}
})
路由文档:
javascript
fastify.get('/users', {
schema: {
description: 'Get all users',
tags: ['Users'],
querystring: {
type: 'object',
properties: {
page: { type: 'integer', default: 1 },
limit: { type: 'integer', default: 10 }
}
},
response: {
200: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'integer' },
name: { type: 'string' }
}
}
}
}
}
}, async (request, reply) => {
return [{ id: 1, name: 'John' }]
})
六、健康检查中间件 #
6.1 @fastify/under-pressure #
系统压力监控。
安装:
bash
npm install @fastify/under-pressure
基本使用:
javascript
fastify.register(require('@fastify/under-pressure'), {
maxEventLoopDelay: 1000,
maxHeapUsedBytes: 100000000,
maxRssBytes: 100000000
})
自定义检查:
javascript
fastify.register(require('@fastify/under-pressure'), {
maxEventLoopDelay: 1000,
customHealthCheck: async function () {
return fastify.db.isConnected()
}
})
fastify.get('/health', async (request, reply) => {
return {
status: 'ok',
memory: fastify.memoryUsage(),
eventLoopDelay: fastify.eventLoopDelay()
}
})
七、最佳实践 #
7.1 中间件注册顺序 #
javascript
const fastify = require('fastify')()
fastify.register(require('@fastify/sensible'))
fastify.register(require('@fastify/helmet'))
fastify.register(require('@fastify/cors'))
fastify.register(require('@fastify/rate-limit'), {
max: 100,
timeWindow: '1 minute'
})
fastify.register(require('@fastify/jwt'), {
secret: process.env.JWT_SECRET
})
fastify.register(require('./routes'))
fastify.listen({ port: 3000 })
7.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'))
fastify.register(require('@fastify/helmet'), {
contentSecurityPolicy: {
// 生产环境配置
}
})
}
八、总结 #
本章我们学习了:
- 安全中间件:helmet、cors、rate-limit
- 认证中间件:jwt、cookie、session
- 数据中间件:multipart、static
- 压缩中间件:compress
- API文档:swagger
- 健康检查:under-pressure
- 最佳实践:注册顺序、环境配置
接下来让我们学习请求与响应!
最后更新:2026-03-28