Appearance
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'); // 10485762. type-is - Content-Type 检查
检查请求的 Content-Type:
javascript
typeis(req, 'application/json'); // true/false3. 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杜"公众号,获取更多技术内容和最新动态
