常用中间件 #

一、安全中间件 #

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: {
      // 生产环境配置
    }
  })
}

八、总结 #

本章我们学习了:

  1. 安全中间件:helmet、cors、rate-limit
  2. 认证中间件:jwt、cookie、session
  3. 数据中间件:multipart、static
  4. 压缩中间件:compress
  5. API文档:swagger
  6. 健康检查:under-pressure
  7. 最佳实践:注册顺序、环境配置

接下来让我们学习请求与响应!

最后更新:2026-03-28