Skip to content

body-parser 源代码导览

项目结构

body-parser 的源代码结构:

body-parser/
├── lib/
│   ├── types/
│   │   ├── json.js      # JSON 解析器
│   │   ├── urlencoded.js # URL-encoded 解析器
│   │   └── raw.js       # 原始数据解析器
│   └── read.js          # 请求体读取工具
└── index.js             # 主入口

核心文件

1. index.js - 主入口

主入口文件导出所有解析器:

javascript
module.exports = json;
module.exports.json = json;
module.exports.urlencoded = urlencoded;
module.exports.text = text;
module.exports.raw = raw;

2. lib/types/json.js - JSON 解析器

JSON 解析器的核心逻辑:

javascript
function json(options) {
  // 默认选项
  const opts = options || {};
  
  // 类型检查
  const type = opts.type || 'application/json';
  
  // 返回中间件
  return function jsonParser(req, res, next) {
    // 检查 Content-Type
    if (!typeis(req, type)) {
      return next();
    }
    
    // 读取请求体
    read(req, res, next, {
      encoding: 'utf8',
      limit: opts.limit,
      verify: opts.verify
    }, function (err, body) {
      if (err) {
        return next(err);
      }
      
      try {
        // 解析 JSON
        req.body = JSON.parse(body, opts.reviver);
      } catch (e) {
        err = new SyntaxError(e.message);
        err.status = 400;
        return next(err);
      }
      
      next();
    });
  };
}

3. lib/types/urlencoded.js - URL-encoded 解析器

URL-encoded 解析器的核心逻辑:

javascript
function urlencoded(options) {
  // 默认选项
  const opts = options || {};
  
  // 类型检查
  const type = opts.type || 'application/x-www-form-urlencoded';
  
  // 返回中间件
  return function urlencodedParser(req, res, next) {
    // 检查 Content-Type
    if (!typeis(req, type)) {
      return next();
    }
    
    // 读取请求体
    read(req, res, next, {
      encoding: 'utf8',
      limit: opts.limit,
      verify: opts.verify
    }, function (err, body) {
      if (err) {
        return next(err);
      }
      
      try {
        // 解析 URL-encoded 数据
        if (opts.extended) {
          req.body = qs.parse(body, opts);
        } else {
          req.body = querystring.parse(body, opts);
        }
      } catch (e) {
        err = new SyntaxError(e.message);
        err.status = 400;
        return next(err);
      }
      
      next();
    });
  };
}

4. lib/read.js - 请求体读取工具

请求体读取工具的核心逻辑:

javascript
function read(req, res, next, options, done) {
  // 初始化 buffer
  let length = req.headers['content-length'];
  let limit = typeof options.limit === 'number'
    ? options.limit
    : bytes(options.limit);
  
  // 检查大小限制
  if (length && length > limit) {
    return done(createError(413, 'request entity too large', {
      type: 'entity.too.large'
    }));
  }
  
  // 创建 buffer
  let buffer = Buffer.allocUnsafeSlow(length || 0);
  let pos = 0;
  
  // 监听 data 事件
  req.on('data', function (chunk) {
    // 检查大小限制
    if (pos + chunk.length > limit) {
      req.destroy();
      return done(createError(413, 'request entity too large', {
        type: 'entity.too.large'
      }));
    }
    
    // 复制数据到 buffer
    chunk.copy(buffer, pos);
    pos += chunk.length;
  });
  
  // 监听 end 事件
  req.on('end', function () {
    // 转换为字符串
    let str = buffer.toString(options.encoding || 'utf8', 0, pos);
    
    // 调用验证函数
    if (options.verify) {
      try {
        options.verify(req, res, buffer, options.encoding);
      } catch (err) {
        return done(err);
      }
    }
    
    done(null, str);
  });
}

关键函数

1. typeis() - 类型检查

检查请求的 Content-Type:

javascript
function typeis(req, types) {
  const contentType = req.headers['content-type'];
  
  if (!contentType) {
    return false;
  }
  
  // 解析 Content-Type
  const type = contentType.split(';')[0].trim();
  
  // 检查是否匹配
  return types.includes(type);
}

2. createError() - 创建错误

创建标准化的错误对象:

javascript
function createError(status, message, props) {
  const err = new Error(message);
  err.status = status;
  err.statusCode = status;
  err.expose = true;
  
  Object.assign(err, props);
  
  return err;
}

依赖库

1. bytes - 字节大小解析

解析字节大小字符串:

javascript
bytes('1kb'); // 1024
bytes('1mb'); // 1048576

2. type-is - Content-Type 检查

检查请求的 Content-Type:

javascript
typeis(req, 'application/json'); // true/false

3. qs - 查询字符串解析

解析查询字符串(extended 模式):

javascript
qs.parse('a[b]=c'); // { a: { b: 'c' } }

4. querystring - 查询字符串解析

解析查询字符串(标准模式):

javascript
querystring.parse('a[b]=c'); // { 'a[b]': 'c' }

设计模式

1. 中间件模式

所有解析器都遵循 Express 中间件模式:

javascript
function parser(req, res, next) {
  // 解析逻辑
  next();
}

2. 工厂模式

解析器函数是工厂函数,返回中间件:

javascript
function json(options) {
  return function middleware(req, res, next) {
    // 中间件逻辑
  };
}

3. 策略模式

根据 Content-Type 选择不同的解析策略:

javascript
if (typeis(req, 'application/json')) {
  jsonParser(req, res, next);
} else if (typeis(req, 'application/x-www-form-urlencoded')) {
  urlencodedParser(req, res, next);
}

总结

body-parser 的源代码简洁而高效,通过模块化的设计和流式处理,实现了灵活的请求体解析功能。理解其源代码有助于我们更好地使用和定制请求体解析功能。


架构师AI杜公众号二维码

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