Node.js HTTP Server vs Express.js 对比分析

154 阅读3分钟

原生 Node.js HTTP Server 实现分析

核心概念

  1. 请求处理流程

    • 使用 http.createServer() 创建服务器实例
    • 通过回调函数处理每个请求
    • 手动解析 URL 和请求方法
    • 手动设置响应头和状态码
  2. 路由实现

    const controllers: Record<string, Controller> = {
      '/': (req: Request, res: Response) => {
        const data = services['/']({ name: 'word' })
        res.end(data)
      },
      // ... 其他路由
    }
    
    • 使用对象映射实现路由
    • 需要手动处理 404 情况
    • 路由处理逻辑与业务逻辑分离
  3. 中间件机制

    • 原生实现中没有内置中间件机制
    • 需要手动实现请求处理管道
    • 每个中间件需要显式调用 next()

优点

  • 轻量级,无额外依赖
  • 完全控制请求处理流程
  • 性能开销最小
  • 适合学习 HTTP 协议原理

缺点

  • 需要手动处理很多底层细节
  • 代码结构可能变得复杂
  • 缺乏内置功能(如路由、中间件等)
  • 需要自行实现错误处理

Express.js 实现分析

核心概念

  1. 中间件系统

    • 使用 app.use() 注册中间件
    • 自动处理 next() 调用
    • 支持异步中间件
    • 可以访问和修改请求/响应对象
  2. 常用中间件集成

    // body-parser 中间件
    app.use(express.json())  // 处理 JSON 请求体
    app.use(express.urlencoded({ extended: true }))  // 处理 URL 编码的请求体
    
    // CORS 中间件
    app.use(cors({
      origin: 'http://localhost:3000',
      methods: ['GET', 'POST'],
      allowedHeaders: ['Content-Type']
    }))
    

    body-parser 原理

    • 请求体解析流程

      1. 接收原始请求数据流
      2. 根据 Content-Type 选择解析方式
      3. 将数据流转换为 JavaScript 对象
      4. 挂载到 req.body 供后续中间件使用
    • 原生实现对比

      // 原生 Node.js 实现
      let body = '';
      req.on('data', chunk => {
        body += chunk.toString();
      });
      req.on('end', () => {
        const data = JSON.parse(body);
        // 处理数据...
      });
      
    • 应用场景

      1. 表单提交处理
      // 处理 application/x-www-form-urlencoded 格式
      app.use(express.urlencoded({ extended: true }));
      // 前端表单提交
      // <form method="POST" action="/submit">
      //   <input name="username" value="john">
      //   <input name="password" value="123456">
      // </form>
      
      1. JSON API 开发
      // 处理 application/json 格式
      app.use(express.json());
      // 前端 AJAX 请求
      // fetch('/api/users', {
      //   method: 'POST',
      //   headers: { 'Content-Type': 'application/json' },
      //   body: JSON.stringify({ name: 'John', age: 30 })
      // });
      
      1. 文件上传处理
      // 处理 multipart/form-data 格式
      const multer = require('multer');
      const upload = multer({ dest: 'uploads/' });
      app.post('/upload', upload.single('file'), (req, res) => {
        console.log(req.file); // 文件信息
        console.log(req.body); // 其他表单字段
      });
      
      1. RESTful API 开发
      // 处理复杂的 API 请求体
      app.post('/api/products', express.json(), (req, res) => {
        const { name, price, category, tags } = req.body;
        // 处理产品创建逻辑
      });
      
      1. Webhook 集成
      // 处理第三方服务的回调数据
      app.post('/webhook', express.json(), (req, res) => {
        const { event, data, signature } = req.body;
        // 验证签名并处理事件
      });
      

    CORS 原理

    • 跨域资源共享机制
      1. 浏览器发送预检请求(OPTIONS)
      2. 服务器返回允许的源、方法和头部
      3. 浏览器根据响应决定是否允许实际请求
    • 关键响应头
      // 原生 Node.js 实现
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
      res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
      
  3. 路由系统

    app.get('/', (req, res) => {
      res.send('Hello World')
    })
    
    • 内置路由系统
    • 支持路由参数
    • 支持路由分组
    • 自动处理 404
  4. 请求处理

    • 自动解析请求体
    • 内置静态文件服务
    • 支持模板引擎
    • 内置错误处理

优点

  • 丰富的生态系统
  • 简洁的 API 设计
  • 内置常用功能
  • 易于扩展和维护

缺点

  • 额外的性能开销
  • 可能过度封装
  • 学习曲线相对较陡
  • 依赖第三方中间件

使用场景建议

适合使用原生 Node.js HTTP Server 的场景

  • 学习 HTTP 协议原理
  • 构建简单的 API 服务
  • 对性能要求极高的场景
  • 需要完全控制请求处理流程

适合使用 Express.js 的场景

  • 快速开发 Web 应用
  • 构建复杂的 API 服务
  • 需要丰富的中间件支持
  • 团队协作开发

总结

选择使用原生 Node.js HTTP Server 还是 Express.js,主要取决于项目需求:

  • 如果追求性能和完全控制,选择原生实现
  • 如果追求开发效率和功能丰富,选择 Express.js

理解两者的区别和实现原理,有助于我们更好地选择和使用合适的工具。