🚀 Express 中间件流水线

源码级深度解析

源码级别解析 · express.js, application.js, router/index.js
2026-03-15 | 每日技术深度解读

📚 Express 简介

Express 是 Node.js 最流行的 Web 框架,核心特性是中间件流水线机制

🎯 核心特性

  • 轻量级、高度可扩展
  • 中间件架构灵活
  • 丰富的生态系统
  • 路由系统强大

⚡ 性能优势

  • 异步非阻塞 I/O
  • 中间件按需加载
  • 路由匹配高效
  • 内存占用低

🔄 中间件流水线概览

HTTP Request ↓ [Middleware 1] → next() ↓ [Middleware 2] → next() ↓ [Middleware 3] → next() ↓ [Route Handler] ↓ HTTP Response

核心机制:每个中间件调用 next() 将控制权传递给下一个中间件

🏗️ Express 核心架构

📁 核心模块

  • express.js - 入口文件
  • application.js - 应用对象
  • router/index.js - 路由器
  • router/layer.js - 中间件层

🔧 关键对象

  • app - Express 应用实例
  • req - 请求对象
  • res - 响应对象
  • next - 下一个中间件

⚙️ createApplication() 函数

function createApplication() {
  var app = function(req, res, next) {
    app.handle(req, res, next);
  };

  mixin(app, EventEmitter.prototype, false);
  mixin(app, proto, false);

  app.request = Object.create(req, {
    app: { configurable: true, enumerable: true, writable: true, value: app }
  })

  app.response = Object.create(res, {
    app: { configurable: true, enumerable: true, writable: true, value: app }
  })

  app.init();
  return app;
}

🔑 createApplication 核心逻辑

1. 创建 app 函数

app 本身是一个函数,接收 (req, res, next) 参数

2. 混入原型方法

使用 merge-descriptors 将 EventEmitter 和 application 原型方法混入 app

3. 创建 request/response 对象

基于原型创建,并绑定 app 引用

4. 初始化应用

调用 app.init() 初始化缓存、设置等

📝 app.use() 中间件注册

app.use = function use(fn) {
  var offset = 0;
  var path = '/';

  // 如果第一个参数是路径
  if (typeof fn !== 'function') {
    var arg = fn;
    while (Array.isArray(arg) && arg.length !== 0) {
      arg = arg[0];
    }
    // 第一个参数是路径
    if (typeof arg !== 'function') {
      offset = 1;
      path = fn;
    }
  }

  var fns = flatten(slice.call(arguments, offset));
  
  // 创建 Layer 对象
  var layer = new Layer(path, {
    sensitive: this.enabled('case sensitive routing'),
    strict: this.enabled('strict routing'),
    end: false
  }, fn);

  // 添加到 stack
  this.stack.push(layer);
  
  return this;
};

🔄 app.handle() 请求处理

app.handle = function handle(req, res, callback) {
  var router = this._router;

  // 如果没有路由器,直接结束
  if (!router) {
    debug('no routes defined on app');
    callback || callback = finalhandler(req, res);
    return callback();
  }

  // 调用路由器的 handle 方法
  router.handle(req, res, callback);
};

核心:app.handle 将请求转发给路由器处理

🎯 Router 类架构

Router ├─ stack: Layer[] // 中间件栈 ├─ params: Object // 参数处理函数 ├─ _params: Array // 参数中间件 └─ methods ├─ handle(req, res, out) // 处理请求 ├─ use(path, fn) // 注册中间件 ├─ route(path) // 创建路由 └─ param(name, fn) // 参数处理

⚡ router.handle() 核心逻辑

proto.handle = function handle(req, res, out) {
  var self = this;
  var stack = this.stack;
  var idx = 0;
  
  // next() 函数
  function next(err) {
    // 如果没有更多中间件
    if (idx >= stack.length) {
      setImmediate(out, err);
      return;
    }
    
    var layer = stack[idx++];
    var path = getPathname(req);
    
    // 路径匹配
    if (!layer.match(path)) {
      return next(err);
    }
    
    // 执行中间件
    var fn = layer.handle;
    try {
      fn(req, res, next);
    } catch (err) {
      next(err);
    }
  }
  
  next(); // 开始执行
};

📦 Layer 类设计

function Layer(path, options, fn) {
  this.handle = fn;
  this.name = fn.name || '<anonymous>';
  this.params = undefined;
  this.path = undefined;
  this.regexp = pathRegexp(path, {
    sensitive: options.sensitive,
    strict: options.strict,
    end: options.end
  });
}

Layer.prototype.match = function match(path) {
  // 使用正则匹配路径
  var match = this.regexp.exec(path);
  
  if (!match) {
    return false;
  }
  
  // 提取参数
  this.params = {};
  this.path = match[0];
  
  return true;
};

🔄 next() 链式调用机制

next() 是中间件流水线的核心

  • next() - 调用下一个中间件
  • next(err) - 跳转到错误处理中间件
  • next('route') - 跳过当前路由

错误处理:如果中间件抛出异常或调用 next(err),Express 会跳过后续中间件,直接调用错误处理中间件

⚠️ 错误处理中间件

// 错误处理中间件必须有 4 个参数
app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

识别方式:Express 通过函数参数数量(4 个)识别错误处理中间件

🛣️ 路由匹配算法

路径匹配流程:

  1. 将路径转换为正则表达式
  2. 使用正则匹配请求路径
  3. 提取路径参数(如 :id)
  4. 将参数存储到 req.params

示例:/users/:id → 匹配 /users/123req.params.id = '123'

📊 Express 性能优化

⚡ 优化策略

  • 中间件按需加载
  • 路由分组管理
  • 静态文件缓存
  • 压缩响应内容

🎯 最佳实践

  • 错误处理中间件放最后
  • 使用 async/await 处理异步
  • 避免同步操作
  • 合理使用 next()

🔧 Request 对象扩展

var req = Object.create(http.IncomingMessage.prototype);

// 扩展属性
req.get = function(name) {
  var lc = name.toLowerCase();
  switch (lc) {
    case 'referer':
    case 'referrer':
      return this.headers.referrer || this.headers.referer;
    default:
      return this.headers[lc];
  }
};

req.param = function(name, defaultValue) {
  var params = this.params || {};
  var body = this.body || {};
  var query = this.query || {};
  
  if (params[name] != null) return params[name];
  if (body[name] != null) return body[name];
  if (query[name] != null) return query[name];
  
  return defaultValue;
};

📤 Response 对象扩展

var res = Object.create(http.ServerResponse.prototype);

res.json = function json(obj) {
  var val = obj;
  
  // 允许设置内容类型
  if (!this.get('Content-Type')) {
    this.set('Content-Type', 'application/json');
  }
  
  // 发送 JSON 响应
  return this.send(JSON.stringify(val));
};

res.send = function send(body) {
  var chunk = body;
  
  // 根据内容类型处理
  switch (typeof chunk) {
    case 'string':
      if (!this.get('Content-Type')) {
        this.type('html');
      }
      break;
    case 'boolean':
    case 'number':
    case 'object':
      return this.json(chunk);
  }
  
  // 发送响应
  this.end(chunk);
  return this;
};

🎯 路由方法实现

methods.forEach(function(method){
  app[method] = function(path){
    if (method === 'get' && arguments.length === 1) {
      // app.get('setting') 获取配置
      return this.set(path);
    }
    
    // 创建路由
    var route = this.route(path);
    
    // 调用路由方法
    route[method].apply(route, slice.call(arguments, 1));
    
    return this;
  };
});

// app.route() 实现
app.route = function route(path) {
  var route = new Route(path);
  
  var layer = new Layer(path, {
    sensitive: this.enabled('case sensitive routing'),
    strict: this.enabled('strict routing'),
    end: true
  }, route.dispatch.bind(route));
  
  layer.route = route;
  this.stack.push(layer);
  
  return route;
};

🔄 Route 类设计

Route ├─ path: String // 路由路径 ├─ stack: Layer[] // 路由中间件 └─ methods ├─ all(callback) // 所有方法 ├─ get(callback) // GET 请求 ├─ post(callback) // POST 请求 └─ dispatch(req, res, out) // 路由分发

区别:Router.stack 存储全局中间件,Route.stack 存储特定路由的中间件

⚡ Route.dispatch() 实现

Route.prototype.dispatch = function dispatch(req, res, done) {
  var idx = 0;
  var stack = this.stack;
  var method = req.method.toLowerCase();
  
  function next(err) {
    // 如果有错误或已处理完所有中间件
    if (err && err === 'route') {
      return done();
    }
    
    if (err) {
      return done(err);
    }
    
    if (idx >= stack.length) {
      return done();
    }
    
    var layer = stack[idx++];
    
    // 检查方法是否匹配
    if (layer.method && layer.method !== method) {
      return next(err);
    }
    
    // 执行中间件
    try {
      layer.handle_request(req, res, next);
    } catch (err) {
      next(err);
    }
  }
  
  next();
};

🔍 参数处理:app.param()

app.param = function param(name, fn) {
  // 参数处理中间件映射
  (this.params[name] = this.params[name] || []).push(fn);
  
  return this;
};

// 使用示例
app.param('userId', function(req, res, next, id) {
  User.findById(id, function(err, user) {
    if (err) return next(err);
    if (!user) return next(new Error('User not found'));
    
    req.user = user;
    next();
  });
});

app.get('/users/:userId', function(req, res) {
  res.json(req.user);  // req.user 已通过 param 中间件加载
});

🎨 中间件类型对比

类型 用途 示例
应用级中间件 全局处理 app.use(logger)
路由级中间件 特定路由 router.use(auth)
错误处理中间件 错误捕获 app.use(errHandler)
内置中间件 静态文件 express.static()
第三方中间件 扩展功能 cors(), helmet()

🔗 中间件执行顺序

Request ↓ [1] express.json() - 解析请求体 ↓ [2] cors() - 跨域处理 ↓ [3] helmet() - 安全头 ↓ [4] morgan() - 日志记录 ↓ [5] 路由中间件 - 业务逻辑 ↓ [6] 错误处理 - 异常捕获 ↓ Response

💡 中间件最佳实践

✅ 推荐做法

  • 中间件功能单一
  • 合理使用 next()
  • 错误统一处理
  • 异步操作用 try-catch

❌ 避免陷阱

  • 忘记调用 next()
  • 阻塞事件循环
  • 错误处理不当
  • 中间件顺序错误

🔄 异步中间件处理

// ❌ 错误示例:异步错误无法捕获
app.use(async (req, res, next) => {
  const data = await fetchData();  // 如果这里出错
  next();  // 错误不会被捕获
});

// ✅ 正确示例:包装异步错误
app.use(async (req, res, next) => {
  try {
    const data = await fetchData();
    next();
  } catch (err) {
    next(err);  // 传递给错误处理中间件
  }
});

// ✅ 更好的方式:使用 express-async-handler
const asyncHandler = require('express-async-handler');
app.use(asyncHandler(async (req, res, next) => {
  const data = await fetchData();  // 自动捕获错误
  next();
}));

⚡ 性能监控中间件

app.use((req, res, next) => {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = Date.now() - start;
    console.log(`${req.method} ${req.path} - ${res.statusCode} - ${duration}ms`);
  });
  
  next();
});

原理:监听 response 的 'finish' 事件,计算请求处理时间

🔒 安全中间件示例

app.use((req, res, next) => {
  // 设置安全头
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-XSS-Protection', '1; mode=block');
  
  // 防止点击劫持
  res.removeHeader('X-Powered-By');
  
  next();
});

推荐:使用 helmet() 中间件自动设置安全头

📊 请求日志中间件

function logger(format) {
  format = format || ':method :url :status';
  
  return function(req, res, next) {
    const start = Date.now();
    
    res.on('finish', () => {
      const duration = Date.now() - start;
      const log = format
        .replace(':method', req.method)
        .replace(':url', req.url)
        .replace(':status', res.statusCode)
        .replace(':duration', duration + 'ms');
      
      console.log(log);
    });
    
    next();
  };
}

app.use(logger(':method :url :status - :duration'));

🧪 单元测试中间件

const assert = require('assert');
const request = require('supertest');
const app = express();

// 测试中间件
function testMiddleware(req, res, next) {
  req.testProperty = 'test-value';
  next();
}

describe('测试中间件', () => {
  it('应该设置 testProperty', (done) => {
    request(app.use(testMiddleware))
      .get('/')
      .expect((res) => {
        assert.equal(res.req.testProperty, 'test-value');
      })
      .end(done);
  });
});

🔗 中间件组合模式

// 组合多个中间件
function compose(middlewares) {
  return function(req, res, next) {
    let index = -1;
    
    function dispatch(i) {
      if (i <= index) {
        return next(new Error('next() called multiple times'));
      }
      
      index = i;
      const fn = middlewares[i];
      
      if (!fn) {
        return next();
      }
      
      try {
        fn(req, res, function next(err) {
          if (err) {
            return next(err);
          }
          dispatch(i + 1);
        });
      } catch (err) {
        next(err);
      }
    }
    
    dispatch(0);
  };
}

🎯 Express vs Koa 对比

Express

  • 回调风格
  • 中间件线性执行
  • 内置路由功能
  • 生态成熟

Koa

  • async/await
  • 洋葱模型
  • 轻量核心
  • 现代语法

选择建议:Express 适合快速开发,Koa 适合现代化项目

⚡ Express 性能基准测试

10,000 req/s

测试环境:Node.js v20, 单核 CPU, 1GB 内存

  • 简单路由:15,000 req/s
  • 带中间件:12,000 req/s
  • JSON 解析:10,000 req/s

🔮 Express 5.0 新特性

Express 5.0 带来的改进

  • ✅ Promise 支持
  • ✅ 更好的错误处理
  • ✅ Router 改进
  • ✅ 性能优化
  • ✅ 安全性增强

🚀 Express 生产部署

📦 部署清单

  • 使用 process manager(PM2)
  • 启用 cluster 模式
  • 配置反向代理(Nginx)
  • 启用 HTTPS
  • 设置日志收集

⚡ 性能优化

  • 启用 gzip 压缩
  • 使用 CDN
  • 数据库连接池
  • Redis 缓存
  • 负载均衡

🎨 设计模式:责任链模式

Express 中间件就是责任链模式的实现

Handler → Handler → Handler → Handler ↓ ↓ ↓ ↓ Request → Process → Process → Process → Response
  • 每个中间件都可以处理请求或传递给下一个
  • 支持动态添加/删除处理器
  • 解耦请求发送者和接收者

🎨 设计模式:模板方法模式

Express 应用的生命周期就是模板方法

  1. 初始化应用 - app.init()
  2. 注册中间件 - app.use()
  3. 注册路由 - app.get/post/...
  4. 启动服务器 - app.listen()
  5. 处理请求 - app.handle()

🎨 设计模式:观察者模式

app.on('mount', function(parent) {
  console.log('App mounted');
});

// EventEm

itter 继承
mixin(app, EventEmitter.prototype, false);

// 触发事件
app.emit('mount', parent);
app.emit('error', err);

应用场景:生命周期事件、错误事件、自定义事件

🎨 设计模式:策略模式

// 不同的认证策略
const strategies = {
  jwt: jwtAuth,
  session: sessionAuth,
  basic: basicAuth
};

function authMiddleware(strategy) {
  return function(req, res, next) {
    const authFn = strategies[strategy];
    
    if (!authFn) {
      return next(new Error('Invalid auth strategy'));
    }
    
    authFn(req, res, next);
  };
}

app.use(authMiddleware('jwt'));

🎨 设计模式:装饰器模式

// 装饰 request 对象
function decorateRequest(req, res, next) {
  req.user = null;
  req.isAuthenticated = function() {
    return !!this.user;
  };
  req.login = function(user) {
    this.user = user;
  };
  
  next();
}

app.use(decorateRequest);

// 后续中间件可以使用扩展方法
app.use((req, res, next) => {
  if (req.isAuthenticated()) {
    // ...
  }
});

📚 最佳实践:项目结构

project/ ├─ src/ │ ├─ middleware/ │ │ ├─ auth.js │ │ ├─ error.js │ │ └─ logger.js │ ├─ routes/ │ │ ├─ index.js │ │ ├─ users.js │ │ └─ posts.js │ ├─ controllers/ │ ├─ models/ │ ├─ services/ │ └─ app.js ├─ tests/ └─ package.json

📚 最佳实践:错误处理

// 统一错误处理类
class AppError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
    this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
    this.isOperational = true;
    
    Error.captureStackTrace(this, this.constructor);
  }
}

// 全局错误处理中间件
app.use((err, req, res, next) => {
  err.statusCode = err.statusCode || 500;
  err.status = err.status || 'error';
  
  res.status(err.statusCode).json({
    status: err.status,
    message: err.message
  });
});

📚 最佳实践:环境配置

const config = {
  development: {
    port: 3000,
    db: 'mongodb://localhost/dev',
    jwtSecret: 'dev-secret'
  },
  production: {
    port: process.env.PORT || 8080,
    db: process.env.DB_URL,
    jwtSecret: process.env.JWT_SECRET
  }
};

const env = process.env.NODE_ENV || 'development';
module.exports = config[env];

推荐:使用 dotenv 管理环境变量

📚 最佳实践:API 设计

✅ RESTful API

  • GET /users
  • POST /users
  • PUT /users/:id
  • DELETE /users/:id

⚠️ 统一响应格式

{
  "success": true,
  "data": {},
  "message": "OK"
}

🔧 调试技巧

// 启用调试日志
DEBUG=express:* node app.js

// 自定义调试
const debug = require('debug')('app:middleware');

app.use((req, res, next) => {
  debug(`${req.method} ${req.url}`);
  next();
});

调试模块:使用 debug 模块分类输出调试信息

📊 性能监控工具

📈 监控指标

  • 响应时间
  • 请求吞吐量
  • 错误率
  • CPU/内存使用

🔧 工具推荐

  • New Relic
  • Datadog
  • Prometheus
  • PM2 Monitor

🔒 安全最佳实践

10 大安全建议

  1. 使用 helmet() 中间件
  2. 启用 HTTPS
  3. 防止 SQL 注入
  4. 防止 XSS 攻击
  5. 限制请求速率(rate-limit)
  6. 验证用户输入
  7. 使用安全的 session
  8. 定期更新依赖
  9. 隐藏敏感信息
  10. 启用 CORS 策略

🔗 Express 生态系统

📦 常用中间件

  • body-parser - 请求体解析
  • cors - 跨域支持
  • helmet - 安全头
  • morgan - 日志
  • compression - 压缩

🚀 扩展框架

  • NestJS - 企业级框架
  • Feathers - 实时 API
  • LoopBack - API 平台
  • Sails - MVC 框架

📖 学习资源

  • 官方文档 - https://expressjs.com/
  • Express 源码 - https://github.com/expressjs/express
  • Express 最佳实践 - https://expressjs.com/en/advanced/best-practice-performance.html
  • Node.js 设计模式 - 书籍推荐

✅ 总结:核心要点

🎯 架构设计

  • 中间件流水线机制
  • Layer 抽象层
  • Router 路由系统
  • 请求/响应对象扩展

⚡ 性能优化

  • 中间件按需加载
  • 异步非阻塞
  • 缓存策略
  • 集群模式

🎉 完成!

51 页

Express 中间件流水线源码解读

从 createApplication 到 next() 链式调用

从 Layer 抽象到 Router 路由系统

完整拆解 Express 核心架构

访问更多技术文章:https://atcfu.com/ai-articles/