koa-bodyparser源码解析

介绍

A body parser for koa, based on co-body. support json, form and text type body.

意思是koa的body解析器,基于co-body,支持jsonformtext类型的请求体。

demo:

1
2
3
4
5
6
7
8
9
10
11
var Koa = require('koa');
var bodyParser = require('koa-bodyparser');

var app = new Koa();
app.use(bodyParser());

app.use(async ctx => {
// the parsed body will store in ctx.request.body
// if nothing was parsed, body will be an empty object {}
ctx.body = ctx.request.body;
});

源码 koa-bodyparser 4.3.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
'use strict';
const parse = require('co-body');
const copy = require('copy-to');

/**
* @param [Object] opts
* - {String} jsonLimit default '1mb'
* - {String} formLimit default '56kb'
* - {string} encoding default 'utf-8'
* - {Object} extendTypes
*/

module.exports = function (opts) {
opts = opts || {};
const { detectJSON } = opts;
const { onerror } = opts;

// 获取可用类型,以及各类型可用的布尔值
const enableTypes = opts.enableTypes || ['json', 'form'];
const enableForm = checkEnable(enableTypes, 'form');
const enableJson = checkEnable(enableTypes, 'json');
const enableText = checkEnable(enableTypes, 'text');
const enableXml = checkEnable(enableTypes, 'xml');

opts.detectJSON = undefined;
opts.onerror = undefined;

// 使 co-body 返回 raw body
opts.returnRawBody = true;

// 默认的 json 类型
const jsonTypes = [
'application/json',
'application/json-patch+json',
'application/vnd.api+json',
'application/csp-report'
];

// 默认的 form 类型
const formTypes = ['application/x-www-form-urlencoded'];

// 默认的 text 类型
const textTypes = ['text/plain'];

// 默认的 xml 类型
const xmlTypes = ['text/xml', 'application/xml'];

// 格式化成对应类型的参数
const jsonOpts = formatOptions(opts, 'json');
const formOpts = formatOptions(opts, 'form');
const textOpts = formatOptions(opts, 'text');
const xmlOpts = formatOptions(opts, 'xml');

// 这里通过参数扩展自定义的type类型
const extendTypes = opts.extendTypes || {};
extendType(jsonTypes, extendTypes.json);
extendType(formTypes, extendTypes.form);
extendType(textTypes, extendTypes.text);
extendType(xmlTypes, extendTypes.xml);

// 返回中间件
return async function bodyParser(ctx, next) {
// 如果请求体为空或禁用则跳出
if (ctx.request.body !== undefined || ctx.disableBodyParser)
return await next();
try {
const res = await parseBody(ctx);
ctx.request.body = 'parsed' in res ? res.parsed : {};
if (ctx.request.rawBody === undefined) ctx.request.rawBody = res.raw;
} catch (err) {
if (onerror) {
// 自定义错误处理函数
onerror(err, ctx);
} else {
throw err;
}
}

await next();
};

// 使用co-body的parse转换请求内容
async function parseBody(ctx) {
if (
enableJson &&
((detectJSON && detectJSON(ctx)) || ctx.request.is(jsonTypes))
) {
return await parse.json(ctx, jsonOpts);
}

if (enableForm && ctx.request.is(formTypes)) {
return await parse.form(ctx, formOpts);
}

if (enableText && ctx.request.is(textTypes)) {
return (await parse.text(ctx, textOpts)) || '';
}

if (enableXml && ctx.request.is(xmlTypes)) {
return (await parse.text(ctx, xmlOpts)) || '';
}

return {};
}
};

function formatOptions(opts, type) {
const res = {};
// 将opts复制到res中并返回
copy(opts).to(res);
res.limit = opts[type + 'Limit'];
return res;
}

function extendType(original, extend) {
if (extend) {
if (!Array.isArray(extend)) {
extend = [extend];
}

extend.forEach(function (extend) {
original.push(extend);
});
}
}

function checkEnable(types, type) {
return types.includes(type);
}

request的is判断:
1
2
3
is (type, ...types) {
return typeis(this.req, type, ...types)
},

​ 可以看到这边bodyparser确实没有过多的逻辑,主要是使用co-body这个库去处理对应类型的数据。

参考链接:

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

给阿姨来一杯卡普基诺~

支付宝
微信