Skip to content

Express 架构分析

高层架构

Express 采用中间件链式的架构,整体可以分为以下几个层次:

┌─────────────────────────────────────────────────┐
│           应用层 (Application)                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  路由    │  │  中间件  │  │  控制器   │   │
│  └──────────┘  └──────────┘  └──────────┘   │
├─────────────────────────────────────────────────┤
│           Express 核心 (Core)                   │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  Router  │  │  Layer   │  │  Request  │   │
│  └──────────┘  └──────────┘  └──────────┘   │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │ Response │  │  App     │  │  View     │   │
│  └──────────┘  └──────────┘  └──────────┘   │
├─────────────────────────────────────────────────┤
│           Node.js HTTP (底层)                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │ http     │  │  events  │  │  stream   │   │
│  └──────────┘  └──────────┘  └──────────┘   │
└─────────────────────────────────────────────────┘

核心模块

Application (应用)

Application 是 Express 的核心类,代表一个 Express 应用实例:

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

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

  // 注册中间件
  use(fn) {
    const layer = new Layer('/', fn);
    this.stack.push(layer);
  }

  // 注册路由
  get(path, fn) {
    const route = new Route(path);
    route.get(fn);
    const layer = new Layer(path, route.dispatch.bind(route));
    this.stack.push(layer);
  }

  // 处理请求
  handle(req, res, done) {
    let index = 0;

    const next = (err) => {
      if (err) {
        return done(err);
      }

      if (index >= this.stack.length) {
        return done();
      }

      const layer = this.stack[index++];
      layer.handle_request(req, res, next);
    };

    next();
  }
}

Router (路由器)

Router 负责路由匹配和分发:

javascript
class Router {
  constructor() {
    this.stack = [];
  }

  // 添加路由
  get(path, fn) {
    const layer = new Layer(path, fn);
    layer.method = 'GET';
    this.stack.push(layer);
  }

  // 处理请求
  handle(req, res, next) {
    const method = req.method;
    const url = req.url;

    for (const layer of this.stack) {
      if (layer.match(url) && layer.method === method) {
        return layer.handle_request(req, res, next);
      }
    }

    next();
  }
}

Layer (层)

Layer 代表中间件或路由的一层:

javascript
class Layer {
  constructor(path, fn) {
    this.path = path;
    this.handle = fn;
    this.method = null;
    this.params = {};
  }

  // 匹配路径
  match(path) {
    if (this.path === path) {
      return true;
    }

    // 支持参数路由
    const paramNames = [];
    const regex = this.pathToRegex(this.path, paramNames);
    const match = path.match(regex);

    if (match) {
      this.params = this.extractParams(match, paramNames);
      return true;
    }

    return false;
  }

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

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

Request (请求)

Request 扩展了 Node.js 的 IncomingMessage:

javascript
class Request {
  constructor(req) {
    this.req = req;
    this.url = req.url;
    this.method = req.method;
    this.headers = req.headers;
    this.query = this.parseQuery(req.url);
    this.params = {};
    this.body = {};
  }

  // 解析查询字符串
  parseQuery(url) {
    const queryIndex = url.indexOf('?');
    if (queryIndex === -1) {
      return {};
    }
    const queryString = url.slice(queryIndex + 1);
    return this.parseQueryString(queryString);
  }

  // 解析查询字符串
  parseQueryString(str) {
    const params = {};
    const pairs = str.split('&');
    for (const pair of pairs) {
      const [key, value] = pair.split('=');
      params[decodeURIComponent(key)] = decodeURIComponent(value || '');
    }
    return params;
  }
}

Response (响应)

Response 扩展了 Node.js 的 ServerResponse:

javascript
class Response {
  constructor(res) {
    this.res = res;
    this.statusCode = 200;
    this.headers = {};
    this.locals = {};
  }

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

  // 发送 JSON
  json(obj) {
    this.setHeader('Content-Type', 'application/json');
    this.send(JSON.stringify(obj));
  }

  // 发送响应
  send(data) {
    this.res.writeHead(this.statusCode, this.headers);
    this.res.end(data);
  }

  // 设置响应头
  setHeader(name, value) {
    this.headers[name] = value;
    return this;
  }

  // 渲染模板
  render(view, options, callback) {
    // 实现模板渲染
  }
}

数据流

请求处理流程

HTTP 请求


┌─────────────────────────────────────┐
│  HTTP 服务器                      │
│  - 接收请求                       │
│  - 创建 req/res 对象               │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  Express 应用                      │
│  - 创建 Request 对象               │
│  - 创建 Response 对象              │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  中间件链                         │
│  - 执行中间件 1                   │
│  - 执行中间件 2                   │
│  - 执行中间件 N                   │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  路由处理                         │
│  - 匹配路由                       │
│  - 提取参数                       │
│  - 执行路由处理器                 │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  控制器                           │
│  - 处理业务逻辑                   │
│  - 生成响应数据                   │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  响应生成                         │
│  - 设置状态码                     │
│  - 设置响应头                     │
│  - 发送响应体                     │
└───────────────┬───────────────────┘


HTTP 响应

中间件链流程

请求进入


┌─────────────────────────────────────┐
│  中间件 1                        │
│  - 处理请求                       │
│  - 调用 next()                    │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  中间件 2                        │
│  - 处理请求                       │
│  - 调用 next()                    │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  中间件 N                        │
│  - 处理请求                       │
│  - 调用 next()                    │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  路由处理器                       │
│  - 执行业务逻辑                   │
│  - 发送响应                       │
└───────────────┬───────────────────┘


响应返回

并发模型

单线程模型

Express 基于 Node.js 的单线程模型:

主线程
┌─────────────────────────────────────┐
│  事件循环                         │
│  - 接收请求                       │
│  - 执行中间件                     │
│  - 处理路由                       │
│  - 发送响应                       │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  线程池 (libuv)                  │
│  - 文件 I/O                       │
│  - DNS 解析                       │
│  - 加密操作                       │
└─────────────────────────────────────┘

并发处理

Express 可以处理大量并发请求:

请求 1 ──┐
          ├──► 中间件链 ──► 响应
请求 2 ──┤

请求 3 ──┤

请求 N ──┘

容错策略

错误处理

Express 提供多种错误处理机制:

  1. 错误中间件:专门处理错误的中间件
  2. 默认错误处理:Express 内置的错误处理
  3. 异步错误:使用 next(err) 传递错误
  4. 错误日志:记录错误信息

错误处理流程

请求进入


┌─────────────────────────────────────┐
│  中间件 1                        │
│  - 发生错误                       │
│  - 调用 next(err)                 │
└───────────────┬───────────────────┘


┌─────────────────────────────────────┐
│  错误处理中间件                   │
│  - 接收错误对象                   │
│  - 处理错误                       │
│  - 发送错误响应                   │
└───────────────┬───────────────────┘


错误响应

可扩展性杠杆

水平扩展

Express 支持多种水平扩展方式:

  1. 负载均衡:使用 Nginx、HAProxy 等负载均衡器
  2. 集群模式:使用 Node.js cluster 模块
  3. 微服务:拆分为多个独立的服务
  4. 容器化:使用 Docker 进行容器化部署

垂直扩展

Express 也支持垂直扩展:

  1. 增加 CPU 核心:利用多核 CPU
  2. 增加内存:提高内存限制
  3. 优化代码:减少 CPU 和内存使用
  4. 使用缓存:减少重复计算和 I/O 操作

中间件扩展

Express 的中间件机制提供了强大的扩展能力:

  1. 自定义中间件:编写自己的中间件
  2. 第三方中间件:使用丰富的第三方中间件
  3. 中间件组合:组合多个中间件
  4. 条件中间件:根据条件加载中间件

总结

Express 的架构设计体现了"简单、灵活、可扩展"的理念。通过中间件链、路由系统和扩展的请求/响应对象,Express 提供了一个强大而灵活的 Web 框架。理解 Express 的架构有助于我们更好地使用和扩展 Express 应用。


架构师AI杜公众号二维码

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