Express.js 中间件指南

Express.js 中间件完整参考,涵盖内置、第三方和自定义中间件,附带实用代码示例。

1. 中间件基础 — app.use()

中间件函数可访问 reqresnext,必须调用 next() 将控制权交给下一个中间件。

const express = require('express');
const app = express();

// 应用级中间件(每个请求都会执行)
app.use((req, res, next) => {
  console.log(`${req.method} ${req.path} — ${Date.now()}`);
  next(); // 必须调用 next() 或发送响应
});

// 路径范围中间件(仅对 /api/* 生效)
app.use('/api', (req, res, next) => {
  req.apiVersion = 'v1';
  next();
});

// 一次注册多个中间件
app.use(express.json(), express.urlencoded({ extended: true }));

app.listen(3000);

2. 自定义中间件模式

请求日志

// middleware/logger.js
function requestLogger(options = {}) {
  return (req, res, next) => {
    const start = Date.now();
    res.on('finish', () => {
      const duration = Date.now() - start;
      console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl} ${res.statusCode} ${duration}ms`);
    });
    next();
  };
}
module.exports = requestLogger;

// 使用
app.use(requestLogger());

认证中间件

const jwt = require('jsonwebtoken');

function requireAuth(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: '缺少 token' });
  }
  try {
    const token = authHeader.slice(7);
    req.user = jwt.verify(token, process.env.JWT_SECRET);
    next();
  } catch (err) {
    res.status(401).json({ error: 'token 无效' });
  }
}

// 基于角色的工厂函数
function requireRole(...roles) {
  return (req, res, next) => {
    if (!roles.includes(req.user?.role)) {
      return res.status(403).json({ error: '无权限' });
    }
    next();
  };
}

// 使用
app.get('/admin', requireAuth, requireRole('admin'), (req, res) => {
  res.json({ message: '欢迎管理员' });
});

3. 错误处理中间件

错误中间件接收 4 个参数:(err, req, res, next),必须在最后注册。

// 异步错误包装器 — 避免在每个路由中写 try/catch
const asyncHandler = fn => (req, res, next) =>
  Promise.resolve(fn(req, res, next)).catch(next);

class AppError extends Error {
  constructor(message, statusCode = 500) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;
  }
}

app.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await User.findById(req.params.id);
  if (!user) throw new AppError('用户不存在', 404);
  res.json(user);
}));

// 全局错误处理(必须放在最后)
app.use((err, req, res, next) => {
  const status = err.statusCode || 500;
  const message = err.isOperational ? err.message : '服务器内部错误';
  res.status(status).json({ error: message });
});

4. CORS 中间件

const cors = require('cors');

// 简单配置 — 允许所有来源
app.use(cors());

// 生产环境配置
const corsOptions = {
  origin: (origin, callback) => {
    const allowed = ['https://app.example.com', 'https://admin.example.com'];
    if (!origin || allowed.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('不允许的来源'));
    }
  },
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400,
};
app.use(cors(corsOptions));

5. Body-Parser 与 Helmet

const helmet = require('helmet');

// Helmet — 设置安全 HTTP 头
app.use(helmet());

// 精细配置
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", 'data:', 'https:'],
    },
  },
  hsts: { maxAge: 31536000, includeSubDomains: true },
}));

// 请求体解析(Express 4.16+ 内置)
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true }));

6. 中间件执行顺序

顺序中间件作用
1helmet()安全头 — 最先执行
2cors()CORS 头
3express.json()解析请求体
4rateLimit()限流
5requireAuth()身份认证
6路由业务逻辑
7errorHandler必须最后注册