Express中间件(Middleware)详解:从零开始掌握(3)

实用中间件模式25例

1. 基础增强模式

请求属性扩展
javascript 复制代码
function extendRequest() {
  return (req, res, next) => {
    req.getClientLanguage = () => {
      return req.headers['accept-language']?.split(',')[0] || 'en';
    };
    next();
  };
}
响应时间头
javascript 复制代码
function responseTime() {
  return (req, res, next) => {
    const start = Date.now();
    res.on('finish', () => {
      res.setHeader('X-Response-Time', `${Date.now() - start}ms`);
    });
    next();
  };
}

2. 安全相关中间件

CSRF防护
javascript 复制代码
function csrfProtection() {
  return (req, res, next) => {
    if (['POST', 'PUT', 'DELETE'].includes(req.method)) {
      const csrfToken = req.headers['x-csrf-token'];
      if (!csrfToken || csrfToken !== req.session.csrfToken) {
        return res.status(403).send('Invalid CSRF token');
      }
    }
    next();
  };
}
CORS配置
javascript 复制代码
function cors(options = {}) {
  return (req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', options.origin || '*');
    res.setHeader('Access-Control-Allow-Methods', options.methods || 'GET,POST,PUT,DELETE');
    res.setHeader('Access-Control-Allow-Headers', options.headers || 'Content-Type,Authorization');
    options.credentials && res.setHeader('Access-Control-Allow-Credentials', 'true');
    req.method === 'OPTIONS' ? res.sendStatus(200) : next();
  };
}

3. 数据转换中间件

请求体格式化
javascript 复制代码
function formatBody() {
  return (req, res, next) => {
    if (req.body) {
      // 去除字符串两端的空格
      Object.keys(req.body).forEach(key => {
        if (typeof req.body[key] === 'string') {
          req.body[key] = req.body[key].trim();
        }
      });
    }
    next();
  };
}
响应数据包装
javascript 复制代码
function wrapResponse() {
  return (req, res, next) => {
    const originalSend = res.send;
    res.send = function(data) {
      const wrapped = {
        status: 'success',
        data: data,
        timestamp: new Date().toISOString()
      };
      originalSend.call(this, wrapped);
    };
    next();
  };
}

高级组合技巧

1. 中间件条件执行

javascript 复制代码
function when(predicate, middleware) {
  return (req, res, next) => {
    predicate(req) ? middleware(req, res, next) : next();
  };
}

// 使用示例
app.use(when(
  req => req.path.startsWith('/api'),
  helmet()
));

2. 中间件并行执行

javascript 复制代码
function parallel(middlewares) {
  return (req, res, next) => {
    let completed = 0;
    const done = () => ++completed === middlewares.length && next();
    
    middlewares.forEach(mw => {
      mw(req, res, done);
    });
  };
}

// 使用示例
app.use(parallel([
  requestLogger,
  responseTime,
  bodyParser.json()
]));

3. 中间件管道

javascript 复制代码
function pipe(...middlewares) {
  return (req, res, next) => {
    const run = i => i < middlewares.length 
      ? middlewares[i](req, res, () => run(i + 1))
      : next();
    run(0);
  };
}

性能优化中间件

1. 缓存中间件

javascript 复制代码
function cache(duration) {
  const cacheStore = new Map();
  
  return (req, res, next) => {
    const key = req.originalUrl;
    const cached = cacheStore.get(key);
    
    if (cached && cached.expiry > Date.now()) {
      return res.send(cached.data);
    }
    
    const originalSend = res.send;
    res.send = function(body) {
      cacheStore.set(key, {
        data: body,
        expiry: Date.now() + duration
      });
      originalSend.call(this, body);
    };
    
    next();
  };
}

2. 压缩中间件

javascript 复制代码
const zlib = require('zlib');

function compression() {
  return (req, res, next) => {
    const acceptEncoding = req.headers['accept-encoding'] || '';
    const originalSend = res.send;
    
    res.send = function(body) {
      if (acceptEncoding.includes('gzip')) {
        res.setHeader('Content-Encoding', 'gzip');
        zlib.gzip(Buffer.from(body), (err, result) => {
          if (err) return originalSend.call(this, body);
          originalSend.call(this, result);
        });
      } else {
        originalSend.call(this, body);
      }
    };
    
    next();
  };
}

调试与错误处理

1. 调试中间件

javascript 复制代码
function debugMiddleware() {
  return (req, res, next) => {
    console.log('--- Request Start ---');
    console.log(`Method: ${req.method}`);
    console.log(`Path: ${req.path}`);
    console.log('Headers:', req.headers);
    console.log('Query:', req.query);
    console.log('Body:', req.body);
    
    const originalSend = res.send;
    res.send = function(body) {
      console.log('--- Response ---');
      console.log(`Status: ${res.statusCode}`);
      console.log('Body:', body);
      originalSend.call(this, body);
    };
    
    next();
  };
}

2. 错误处理增强

javascript 复制代码
function errorHandler() {
  return (err, req, res, next) => {
    console.error(err.stack);
    
    const status = err.status || 500;
    const message = status === 500 ? 'Internal Server Error' : err.message;
    
    res.status(status).json({
      error: {
        message: message,
        code: err.code,
        timestamp: new Date().toISOString(),
        path: req.path
      }
    });
  };
}

实战项目推荐

  1. API网关:组合各种验证、限流、日志中间件
  2. 文件处理管道:创建文件上传处理链
  3. A/B测试框架:基于中间件的流量分配
  4. 多租户系统:通过中间件识别租户

下节将带来以上更加详尽的项目实践。

Express中间件(Middleware)详解:从零开始掌握(4)-CSDN博客

相关推荐
一袋米扛几楼986 天前
【前端】从零开始的搭建顺序指南(技术栈:Node.js + Express + MongoDB + React)book-management
前端·node.js·express
layman05286 天前
node.js 实战——从0开始做一个餐厅预订(express+node+ejs+bootstrap)
node.js·express
白昼的星光@7 天前
使用nodeJs的express+axios+cors做代理
express
键盘飞行员8 天前
使用 Node、Express 和 MongoDB 构建一个项目工程
数据库·mongodb·express
烛阴9 天前
Node.js中必备的中间件大全:提升性能、安全与开发效率的秘密武器
javascript·后端·express
kovlistudio14 天前
红宝书第四十七讲:Node.js服务器框架解析:Express vs Koa 完全指南
服务器·前端·javascript·node.js·express
还是鼠鼠17 天前
Node.js 中 Token 原理简单介绍 + 示例代码
linux·vscode·中间件·node.js·编辑器·vim·express
烛阴18 天前
零基础必看!Express 项目 .env 配置,开发、测试、生产环境轻松搞定!
javascript·后端·express
还是鼠鼠19 天前
Node.js Session 原理简单介绍 + 示例代码
linux·javascript·vscode·node.js·编辑器·vim·express
Kairo_0119 天前
使用 Node.js、Express 和 React 构建强大的 API
react.js·node.js·express