Skip to content

Express 源代码导览

项目结构

Express 的源代码结构如下:

express/
├── lib/
│   ├── application.js        # 应用主类
│   ├── express.js           # 入口文件
│   ├── request.js           # 请求对象扩展
│   ├── response.js          # 响应对象扩展
│   ├── router/
│   │   ├── index.js        # 路由器主类
│   │   ├── layer.js        # 路由层
│   │   └── route.js        # 路由类
│   ├── middleware/          # 内置中间件
│   │   ├── query.js        # 查询解析
│   │   ├── init.js         # 初始化
│   │   └── ...            # 其他中间件
│   ├── utils.js            # 工具函数
│   ├── view.js            # 视图渲染
│   └── ...                # 其他模块
├── test/                  # 测试文件
├── examples/              # 示例代码
├── docs/                 # 文档
└── History.md            # 更新日志

核心文件详解

express.js

express.js 是 Express 的入口文件,负责:

  1. 导出主函数:创建应用实例的工厂函数
  2. 导出核心类:Application、Router、Request、Response
  3. 导出工具函数:各种辅助函数

关键代码片段:

javascript
// 创建应用实例
function express() {
  return new Application();
}

// 导出核心类
express.Application = Application;
express.Router = Router;
express.Request = Request;
express.Response = Response;

// 导出工具函数
express.static = serveStatic;
express.json = bodyParser.json;
express.urlencoded = bodyParser.urlencoded;

module.exports = express;

application.js

application.js 实现了 Express 应用类,主要功能包括:

  1. 应用初始化:设置默认配置
  2. 中间件注册:注册应用级中间件
  3. 路由注册:注册应用级路由
  4. 请求处理:处理传入的 HTTP 请求
  5. 服务器启动:启动 HTTP 服务器

关键代码片段:

javascript
class Application extends EventEmitter {
  constructor() {
    super();
    this.settings = {};
    this.engines = {};
    this.defaultConfiguration();
  }

  // 默认配置
  defaultConfiguration() {
    this.set('env', process.env.NODE_ENV || 'development');
    this.set('x-powered-by', true);
    this.set('subdomain offset', 2);
    this.set('trust proxy', false);
    this.set('query parser', 'extended');
    this.set('jsonp callback name', 'callback');
  }

  // 启动服务器
  listen(port, hostname, backlog, callback) {
    const server = http.createServer(this);
    return server.listen(port, hostname, backlog, callback);
  }

  // 注册中间件
  use(fn) {
    let offset = 0;
    let path = '/';

    // 处理路径参数
    if (typeof fn !== 'function') {
      const arg = fn;
      fn = arguments[offset++];
      if (typeof fn !== 'function') {
        throw new TypeError('Router.use() requires a middleware function');
      }
      path = arg;
    }

    const layer = new Layer(path, {}, fn);
    layer.route = undefined;
    this.stack.push(layer);
    return this;
  }

  // 注册 GET 路由
  get(path, ...handlers) {
    this._route('get', path, handlers);
    return this;
  }

  // 注册路由
  _route(method, path, handlers) {
    const route = this._router.route(path);
    route[method].apply(route, handlers);
    return this;
  }

  // 处理请求
  handle(req, res, done) {
    const router = this._router;
    const finalHandler = done || finalhandler(req, res, {
      env: this.get('env'),
      onerror: this.onerror.bind(this)
    });

    router.handle(req, res, finalHandler);
  }
}

router/index.js

router/index.js 实现了路由器类,主要功能包括:

  1. 路由注册:注册各种 HTTP 方法的路由
  2. 路由匹配:匹配请求路径到对应的路由
  3. 参数提取:提取路径参数
  4. 中间件执行:执行路由中间件

关键代码片段:

javascript
class Router extends EventEmitter {
  constructor() {
    super();
    this.params = {};
    this._params = [];
    this.caseSensitive = undefined;
    this.mergeParams = undefined;
    this.strict = undefined;
    this.stack = [];
  }

  // 注册 GET 路由
  get(path, ...handlers) {
    this._route('get', path, handlers);
    return this;
  }

  // 注册路由
  _route(method, path, handlers) {
    const route = this.route(path);
    route[method].apply(route, handlers);
    return this;
  }

  // 创建路由
  route(path) {
    const route = new Route(path);
    const layer = new Layer(path, {}, route.dispatch.bind(route));
    layer.route = route;
    this.stack.push(layer);
    return route;
  }

  // 处理请求
  handle(req, res, done) {
    let self = this;
    let idx = 0;
    let stack = self.stack;
    let parentUrl = req.baseUrl || '';
    let done = done || finalhandler(req, res, {
      env: this.get('env'),
      onerror: logerror
    });

    req.originalUrl = req.originalUrl || req.url;
    req.baseUrl = parentUrl;
    req.url = parentUrl + req.url;

    function next(err) {
      if (err === 'route') {
        return done();
      }

      if (err === 'router') {
        return done();
      }

      const layerError = err === 'route'
        ? null
        : err;

      // 移除尾随斜杠
      const slashRemoved = trimSlash(req.url);

      // 路由匹配
      const layer = matchLayer(layer, slashRemoved, req);

      if (!layer) {
        return done(layerError);
      }

      // 处理路由
      self.process_params(layer, layerError, req, res, function(err) {
        if (err) {
          return next(err);
        }

        if (layer.route) {
          return layer.handle_request(req, res, next);
        }

        trim_prefix(layer, layerError, req, res, next);
      });
    }

    next();
  }
}

router/layer.js

router/layer.js 实现了路由层类,主要功能包括:

  1. 路径匹配:匹配请求路径
  2. 参数提取:提取路径参数
  3. 中间件执行:执行中间件函数

关键代码片段:

javascript
class Layer {
  constructor(path, options, fn) {
    this.handle = fn;
    this.name = fn.name || '<anonymous>';
    this.params = undefined;
    this.path = undefined;
    this.regexp = pathRegexp(path, this.keys = [], options);

    if (path === '/' && !this.regexp.fast_slash) {
      this.regexp.fast_slash = true;
    }
  }

  // 匹配路径
  match(path) {
    let match;

    if (path != null) {
      // 快速路径匹配
      if (this.regexp.fast_slash) {
        this.params = {};
        this.path = '';
        return true;
      }

      // 正则匹配
      match = this.regexp.exec(path);
    }

    if (!match) {
      return false;
    }

    // 提取参数
    this.params = {};
    this.path = match[0];

    const keys = this.keys;
    const params = this.params;

    for (let i = 1; i < match.length; i++) {
      const key = keys[i - 1];
      const prop = key.name;
      const val = decode_param(match[i]);

      if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
        params[prop] = val;
      }
    }

    return true;
  }

  // 处理请求
  handle_request(req, res, next) {
    const fn = this.handle;

    try {
      fn(req, res, next);
    } catch (err) {
      next(err);
    }
  }

  // 处理错误
  handle_error(err, req, res, next) {
    const fn = this.handle;

    if (fn.length !== 4) {
      return next(err);
    }

    try {
      fn(err, req, res, next);
    } catch (err) {
      next(err);
    }
  }
}

request.js

request.js 扩展了 Node.js 的 IncomingMessage,主要功能包括:

  1. 查询解析:解析查询字符串
  2. 参数访问:访问路径参数
  3. 属性访问:便捷的属性访问方法

关键代码片段:

javascript
const req = Object.create(http.IncomingMessage.prototype);

// 查询参数
Object.defineProperty(req, 'query', {
  configurable: true,
  enumerable: true,
  get: function() {
    const querystring = this._querystring || (this._querystring = parseUrl(this).query);
    return this._query || (this._query = parseQuery(querystring));
  },
  set: function(val) {
    this._query = val;
  }
});

// 路径参数
Object.defineProperty(req, 'params', {
  configurable: true,
  enumerable: true,
  get: function() {
    return this._params;
  },
  set: function(val) {
    this._params = val;
  }
});

// 路由路径
Object.defineProperty(req, 'path', {
  configurable: true,
  enumerable: true,
  get: function() {
    return parseUrl(this).pathname;
  }
});

// 检查请求类型
req.get = req.header = function header(name) {
  const lc = name.toLowerCase();
  switch (lc) {
    case 'referer':
    case 'referrer':
      return this.headers.referrer || this.headers.referer || '';
    default:
      return this.headers[lc] || '';
  }
};

// 检查内容类型
req.is = function(types) {
  const arr = types;
  const type = this.get('Content-Type');

  if (!type) {
    return false;
  }

  if (!Array.isArray(types)) {
    types = arr = [types];
  }

  for (let i = 0; i < types.length; i++) {
    if (typeis(type, types[i])) {
      return types[i];
    }
  }

  return false;
};

module.exports = req;

response.js

response.js 扩展了 Node.js 的 ServerResponse,主要功能包括:

  1. 状态码设置:设置 HTTP 状态码
  2. 响应头发送:设置和发送响应头
  3. 响应体发送:发送各种格式的响应体
  4. 模板渲染:渲染模板引擎

关键代码片段:

javascript
const res = Object.create(http.ServerResponse.prototype);

// 设置状态码
res.status = function status(code) {
  this.statusCode = code;
  return this;
};

// 设置响应头
res.set = res.header = function header(field, val) {
  if (arguments.length === 2) {
    const value = Array.isArray(val) ? val.map(String) : String(val);
    const name = typeof field === 'string'
      ? field.toLowerCase()
      : field;

    this.setHeader(name, value);
  } else {
    for (const key in field) {
      this.set(key, field[key]);
    }
  }
  return this;
};

// 发送响应
res.send = function send(body) {
  const chunk = body;
  const encoding = 'utf8';
  const req = this.req;
  const type = this.get('Content-Type');

  // 设置状态码
  this.statusCode = this.statusCode || 200;

  // 发送 JSON
  if (Buffer.isBuffer(body)) {
    if (!type) {
      this.set('Content-Type', 'application/octet-stream');
    }
    this.end(chunk);
  } else if (typeof body === 'string') {
    if (!type) {
      this.set('Content-Type', 'text/html');
    }
    this.end(chunk, encoding);
  } else if (typeof body === 'object') {
    if (body === null) {
      body = null;
    } else if (Buffer.isBuffer(body)) {
      if (!type) {
        this.set('Content-Type', 'application/octet-stream');
      }
    } else {
      return this.json(body);
    }
  } else {
    this.end(chunk, encoding);
  }

  return this;
};

// 发送 JSON
res.json = function json(obj) {
  const body = JSON.stringify(obj);
  if (!this.get('Content-Type')) {
    this.set('Content-Type', 'application/json');
  }
  return this.send(body);
};

// 渲染模板
res.render = function render(view, options, callback) {
  const app = this.req.app;
  const done = callback || finalhandler(this.req, this.res, {
    env: app.get('env'),
    onerror: logerror
  });

  options = options || {};

  // 渲染视图
  app.render(view, options, (err, str) => {
    if (err) {
      return done(err);
    }
    this.send(str);
  });
};

module.exports = res;

关键算法

路由匹配算法

路由匹配使用正则表达式和参数提取:

javascript
function pathRegexp(path, keys, options) {
  options = options || {};
  const sensitive = options.sensitive;
  const strict = options.strict;
  const end = options.end !== false;
  const delimiter = options.delimiter || '/';
  const endsWith = [].concat(options.endsWith || []).map(escapeString).filter(Boolean);

  // 转义特殊字符
  let route = '';
  let last = 0;
  let isEndDelimited = false;

  for (let i = 0; i < path.length; i++) {
    const char = path[i];

    if (char === '*') {
      // 通配符
      route += escapeRegExp(last, path, i) + '((?:.*))';
      isEndDelimited = true;
      last = i + 1;
    } else if (char === ':') {
      // 参数
      const name = getName(path, i);
      const pattern = getPattern(path, i);

      route += escapeRegExp(last, path, i) + '(?:' + pattern + ')';
      keys.push({ name, optional: false, offset: i });
      i += name.length + pattern.length;
      last = i + 1;
    }
  }

  route += escapeRegExp(last, path, path.length);

  // 添加结束匹配
  if (end) {
    if (!strict) {
      route += '(?:' + delimiter + ')?';
    }
    if (!isEndDelimited) {
      for (let i = 0; i < endsWith.length; i++) {
        route += '(?=' + endsWith[i] + ')';
      }
    }
  }

  return new RegExp('^' + route + '$', sensitive ? '' : 'i');
}

中间件执行算法

中间件使用链式调用模式:

javascript
function handle(req, res, done) {
  let idx = 0;
  const stack = this.stack;

  function next(err) {
    if (err) {
      // 错误处理
      return done(err);
    }

    if (idx >= stack.length) {
      // 所有中间件执行完毕
      return done();
    }

    const layer = stack[idx++];

    // 匹配路径
    if (!layer.match(req.url)) {
      return next();
    }

    // 执行中间件
    try {
      layer.handle_request(req, res, next);
    } catch (err) {
      next(err);
    }
  }

  next();
}

性能关键点

1. 路由匹配优化

Express 使用正则表达式缓存和快速路径匹配:

  • 正则缓存:编译后的正则表达式被缓存
  • 快速路径:根路径使用快速匹配
  • 参数提取:高效的参数提取算法

2. 中间件执行优化

中间件执行通过以下方式优化:

  • 最小化开销:每个中间件只做一件事
  • 提前终止:可以提前终止中间件链
  • 错误处理:专门的错误处理中间件

3. 请求/响应优化

请求和响应对象通过以下方式优化:

  • 延迟计算:属性按需计算
  • 缓存结果:计算结果被缓存
  • 链式调用:支持方法链式调用

扩展点

1. 自定义中间件

Express 允许编写自定义中间件:

javascript
function customMiddleware(req, res, next) {
  // 处理请求
  req.customProperty = 'value';

  // 继续执行
  next();
}

app.use(customMiddleware);

2. 自定义路由

Express 支持自定义路由:

javascript
const router = express.Router();

router.get('/custom', (req, res) => {
  res.send('Custom route');
});

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

3. 自定义错误处理

Express 支持自定义错误处理:

javascript
function errorHandler(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
}

app.use(errorHandler);

测试策略

Express 使用多种测试策略:

  1. 单元测试:测试单个函数和模块
  2. 集成测试:测试模块之间的交互
  3. 端到端测试:测试完整的请求-响应流程
  4. 性能测试:使用 benchmark 进行性能测试

总结

Express 的源代码展示了其简洁而强大的设计。通过中间件链、路由系统和扩展的请求/响应对象,Express 提供了一个强大而灵活的 Web 框架。理解 Express 的源代码结构有助于我们深入理解其工作原理,并更好地使用和扩展 Express。


架构师AI杜公众号二维码

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态