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博客

相关推荐
烛阴13 小时前
Express + Prisma + MySQL:一站式搭建高效 Node.js 后端服务
javascript·后端·express
Mintopia19 小时前
深入理解与使用 Node.js 的 http-proxy-middleware
javascript·node.js·express
gongzemin2 天前
接口用户权限校验逻辑 (jsonwebtoken使用)
前端·后端·express
你的人类朋友2 天前
关于express中间件的工作原理
javascript·node.js·express
烛阴3 天前
你的 Express 应用还在裸奔?赶紧加上这层错误处理的保护罩!
javascript·后端·express
烛阴4 天前
Express 中间件:Node.js 开发的得力助手
前端·javascript·express
森叶5 天前
利用本地 Express Web 服务解决复杂的 Electron 通信链路的问题
前端·electron·express
还是鼠鼠5 天前
Node.js局部生效的中间件
javascript·vscode·中间件·node.js·json·express
烛阴6 天前
从零到RESTful API:Express路由设计速成手册
javascript·后端·express