阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 常用中间件库推荐与比较

常用中间件库推荐与比较

作者:陈川 阅读数:11120人阅读 分类: Node.js

Express 常用中间件库推荐与比较

Express 作为 Node.js 最流行的 Web 框架之一,其灵活性和可扩展性很大程度上依赖于中间件。选择合适的中间件可以显著提升开发效率和项目质量。以下是一些常用中间件库的详细介绍和对比分析。

请求体解析中间件

body-parser

body-parser 是 Express 中处理 HTTP 请求体的经典中间件,支持 JSON、URL-encoded 和文本格式的解析。

const express = require('express');
const bodyParser = require('body-parser');

const app = express();

// 解析 application/json
app.use(bodyParser.json());
// 解析 application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));

app.post('/api/users', (req, res) => {
  console.log(req.body); // 获取解析后的请求体
  res.send('User created');
});

express.json() 和 express.urlencoded()

Express 4.16.0 开始内置了这两个中间件,功能与 body-parser 类似,推荐优先使用内置方案。

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

比较:

  • body-parser 是独立模块,功能更全面(如支持文本解析)
  • 内置中间件更轻量,适合基本需求

静态文件服务

serve-static

Express 内置的 express.static 中间件基于 serve-static 模块,用于提供静态文件服务。

// 提供 public 目录下的静态文件
app.use(express.static('public'));

// 带虚拟路径前缀
app.use('/static', express.static('public'));

高级配置示例:

app.use('/static', express.static('public', {
  index: false, // 禁用目录索引
  maxAge: '1d', // 设置缓存头
  setHeaders: (res, path) => {
    if (path.endsWith('.gz')) {
      res.set('Content-Encoding', 'gzip');
    }
  }
}));

会话管理

express-session

最常用的会话管理中间件,支持多种存储后端(内存、Redis、MongoDB等)。

const session = require('express-session');

app.use(session({
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true, maxAge: 3600000 }
}));

app.get('/login', (req, res) => {
  req.session.user = { id: 1, name: 'John' };
  res.send('Logged in');
});

cookie-session

将会话数据直接存储在客户端 cookie 中,适合小型会话数据。

const cookieSession = require('cookie-session');

app.use(cookieSession({
  name: 'session',
  keys: ['key1', 'key2'],
  maxAge: 24 * 60 * 60 * 1000 // 24小时
}));

比较:

  • express-session 适合存储大量会话数据
  • cookie-session 更简单但受 cookie 大小限制

安全相关中间件

helmet

通过设置各种 HTTP 头来增强应用安全性。

const helmet = require('helmet');
app.use(helmet());

自定义配置:

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "trusted.cdn.com"]
    }
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true
  }
}));

csurf

CSRF 保护中间件(注意:Express 5 将移除该中间件)。

const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

app.get('/form', csrfProtection, (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});

app.post('/process', csrfProtection, (req, res) => {
  // 验证 CSRF 令牌
  res.send('Form processed');
});

日志记录

morgan

HTTP 请求日志记录器,支持多种预定义格式和自定义格式。

const morgan = require('morgan');

// 使用预定义格式
app.use(morgan('combined'));

// 自定义格式
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));

// 只记录错误请求
app.use(morgan('combined', {
  skip: (req, res) => res.statusCode < 400
}));

winston

更全面的日志解决方案,支持多传输方式和日志级别。

const winston = require('winston');
const expressWinston = require('express-winston');

// 请求日志
app.use(expressWinston.logger({
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'requests.log' })
  ],
  format: winston.format.combine(
    winston.format.colorize(),
    winston.format.json()
  ),
  meta: true,
  msg: "HTTP {{req.method}} {{req.url}}"
}));

// 错误日志
app.use(expressWinston.errorLogger({
  transports: [
    new winston.transports.File({ filename: 'errors.log' })
  ]
}));

路由管理

express.Router

Express 内置的路由系统,支持模块化路由定义。

// routes/users.js
const router = express.Router();

router.get('/', (req, res) => {
  res.send('User list');
});

router.get('/:id', (req, res) => {
  res.send(`User ${req.params.id}`);
});

module.exports = router;

// app.js
const userRoutes = require('./routes/users');
app.use('/users', userRoutes);

express-promise-router

支持异步路由处理的增强版 Router。

const Router = require('express-promise-router');
const router = new Router();

router.get('/async', async (req, res) => {
  const data = await someAsyncOperation();
  res.json(data);
});

app.use(router);

错误处理

errorhandler

开发环境下的错误处理中间件。

const errorHandler = require('errorhandler');

if (process.env.NODE_ENV === 'development') {
  app.use(errorHandler());
}

express-async-errors

简化异步路由的错误处理。

require('express-async-errors');

app.get('/async-error', async (req, res) => {
  throw new Error('Something went wrong');
  // 不需要 try/catch
});

// 全局错误处理
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).send('Something broke!');
});

性能优化

compression

响应压缩中间件,支持 gzip/deflate。

const compression = require('compression');

app.use(compression({
  threshold: 1024, // 只压缩大于1KB的响应
  filter: (req, res) => {
    if (req.headers['x-no-compression']) {
      return false;
    }
    return compression.filter(req, res);
  }
}));

express-rate-limit

API 请求限流中间件。

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15分钟
  max: 100, // 每个IP限制100个请求
  message: 'Too many requests from this IP, please try again later'
});

app.use('/api/', limiter);

数据库集成

connect-redis

Redis 会话存储适配器。

const session = require('express-session');
const RedisStore = require('connect-redis')(session);

app.use(session({
  store: new RedisStore({
    host: 'localhost',
    port: 6379,
    ttl: 86400
  }),
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false
}));

connect-mongo

MongoDB 会话存储适配器。

const MongoStore = require('connect-mongo');

app.use(session({
  store: MongoStore.create({
    mongoUrl: 'mongodb://localhost:27017/session_db',
    ttl: 14 * 24 * 60 * 60 // 14天
  }),
  secret: 'your-secret-key'
}));

文件上传

multer

处理 multipart/form-data 类型的表单数据,主要用于文件上传。

const multer = require('multer');

// 内存存储
const upload = multer();

// 磁盘存储
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    cb(null, Date.now() + '-' + file.originalname);
  }
});

const upload = multer({ storage });

// 单文件上传
app.post('/upload', upload.single('avatar'), (req, res) => {
  console.log(req.file);
  res.send('File uploaded');
});

// 多文件上传
app.post('/photos', upload.array('photos', 12), (req, res) => {
  console.log(req.files);
  res.send('Files uploaded');
});

API 文档生成

swagger-ui-express

为 Express 应用提供 Swagger UI 界面。

const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

apidoc

通过代码注释生成 API 文档。

/**
 * @api {get} /user/:id 获取用户信息
 * @apiName GetUser
 * @apiGroup User
 *
 * @apiParam {Number} id 用户唯一ID
 *
 * @apiSuccess {String} name 用户名
 * @apiSuccess {Number} age 用户年龄
 */
app.get('/user/:id', (req, res) => {
  // 实现代码
});

模板引擎

express-handlebars

Handlebars 模板引擎的 Express 集成。

const exphbs = require('express-handlebars');

app.engine('hbs', exphbs({
  extname: '.hbs',
  defaultLayout: 'main',
  layoutsDir: path.join(__dirname, 'views/layouts'),
  partialsDir: path.join(__dirname, 'views/partials')
}));
app.set('view engine', 'hbs');

app.get('/', (req, res) => {
  res.render('home', { title: 'Home Page' });
});

pug

流行的 Pug (Jade) 模板引擎。

app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));

app.get('/', (req, res) => {
  res.render('index', { title: 'Pug Example', message: 'Hello Pug!' });
});

跨域处理

cors

处理跨域资源共享(CORS)的中间件。

const cors = require('cors');

// 简单使用
app.use(cors());

// 自定义配置
app.use(cors({
  origin: ['https://example.com', 'https://api.example.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  exposedHeaders: ['X-Custom-Header'],
  credentials: true,
  maxAge: 86400
}));

// 路由级配置
app.get('/products/:id', cors(), (req, res) => {
  res.json({ id: req.params.id });
});

测试相关

supertest

用于测试 HTTP 端点的库,常与测试框架配合使用。

const request = require('supertest');
const app = require('../app');

describe('GET /users', () => {
  it('responds with JSON', (done) => {
    request(app)
      .get('/users')
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200, done);
  });
});

node-mocks-http

创建模拟的请求和响应对象用于测试中间件。

const httpMocks = require('node-mocks-http');
const middleware = require('../middleware/logger');

test('logger middleware should log request', () => {
  const req = httpMocks.createRequest({
    method: 'GET',
    url: '/test'
  });
  const res = httpMocks.createResponse();
  const next = jest.fn();

  middleware(req, res, next);

  expect(next).toHaveBeenCalled();
});

实用工具

express-validator

请求数据验证中间件。

const { body, validationResult } = require('express-validator');

app.post('/user', 
  body('username').isLength({ min: 5 }).trim().escape(),
  body('email').isEmail().normalizeEmail(),
  body('age').isInt({ min: 18 }),
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // 处理有效数据
    res.send('User created');
  }
);

express-list-endpoints

列出应用中所有已注册的路由。

const listEndpoints = require('express-list-endpoints');

// 获取所有路由
const allRoutes = listEndpoints(app);
console.log(allRoutes);

// 输出示例:
// [
//   { path: '/', methods: ['GET'] },
//   { path: '/users', methods: ['GET', 'POST'] }
// ]

微服务相关

express-gateway

构建 API 网关的框架。

// gateway.config.yml
http:
  port: 8080
apiEndpoints:
  api:
    host: localhost
    paths: '/ip'
serviceEndpoints:
  httpbin:
    url: 'https://httpbin.org'
policies:
  - proxy
pipelines:
  default:
    apiEndpoints:
      - api
    policies:
      - proxy:
          - action:
              serviceEndpoint: httpbin
              changeOrigin: true

express-http-proxy

HTTP 代理中间件。

const proxy = require('express-http-proxy');

app.use('/proxy', proxy('http://example.com', {
  proxyReqPathResolver: (req) => {
    return req.url;
  },
  userResDecorator: (proxyRes, proxyResData, userReq, userRes) => {
    const data = JSON.parse(proxyResData.toString());
    data.customField = 'proxied';
    return JSON.stringify(data);
  }
}));

实时通信

express-ws

为 Express 添加 WebSocket 支持。

const expressWs = require('express-ws')(app);

app.ws('/echo', (ws, req) => {
  ws.on('message', (msg) => {
    ws.send(msg);
  });
});

// 同时支持HTTP和WebSocket
app.get('/echo', (req, res) => {
  res.send('Use WebSocket endpoint');
});

socket.io

流行的实时通信库,与 Express 集成良好。

const http = require('http');
const socketIo = require('socket.io');

const server = http.createServer(app);
const io = socketIo(server);

io.on('connection', (socket) => {
  console.log('New client connected');
  
  socket.on('chat message', (msg) => {
    io.emit('chat message', msg);
  });

  socket.on('disconnect', () => {
    console.log('Client disconnected');
  });
});

server.listen(3000);

国际化

i18next-express-middleware

国际化(i18n)中间件。

const i18next = require('i18next');
const i18nextMiddleware = require('i18next-express-middleware');

i18next
  .use(i18nextMiddleware.LanguageDetector)
  .init({
    fallbackLng: 'en',
    resources: {
      en: { translation: require('./locales/en.json') },
      zh: { translation: require('./locales/zh.json') }
    }
  });

app.use(i18nextMiddleware.handle(i18next));

app.get('/', (req, res) => {
  res.send(req.t('welcome_message'));
});

监控与指标

express-status-monitor

实时应用监控仪表盘。

const expressStatusMonitor = require('express-status-monitor');

app.use(expressStatusMonitor({
  path: '/status',
  spans: [
    { interval: 1, retention: 60 }, // 1分钟采样,保留60个数据点
    { interval: 5, retention: 60 },
    { interval: 15, retention: 60 }
  ],
  chartVisibility: {
    cpu: true,
    mem: true,
    load: true,
    responseTime: true,
    rps: true,
    statusCodes: true
  }
}));

prom-client

Prometheus 监控指标收集。

const promBundle = require('express-prom-bundle');
const metricsMiddleware = promBundle({
  includeMethod: true,
  includePath: true,
  customLabels: { project_name: 'hello_world' },
  promClient: {
    collectDefaultMetrics: {
      timeout: 1000
    }
  }
});

app.use(metricsMiddleware);

// 暴露指标端点
app.get('/metrics', (req, res) => {
  res.set('Content-Type', promBundle.register.contentType);
  res.end(promBundle.register.metrics());
});

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌