为什么使用koa-body?
在使用XMLHttpRequest2发送的FormData数据时,koa服务中除koa-body外,busboy、body-parse、multer、formidable、multiparty,均无法正确获取,也是经过经过测试发现的问题。
koa-body
koa中间件,一个功能齐全的请求体解析器。支持multipart,urlencoded和json请求体。提供与Express的bodyParser、multer相同的功能。
项目内安装
npm install koa-body 或者 yarn add koa-body
支持请求类型
- multipart/form-data
- application/x-www-urlencoded
- application/json
基本使用案例
const Koa = require('koa');
const koaBody = require('koa-body');
const app = new Koa();
app.use(koaBody());
app.use(ctx => { // 获取参数体中的属性和值
console.log(`files:${util.inspect(ctx.request.body.fields)}; body:${util.inspect(ctx.request.body.files)}`);
ctx.body = ctx.request.body;
});
app.listen(3000);
- 请求示例和结果
$ node index.js
$ curl -i http://localhost:3000/users -d "name=test"
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 29
Date: Wed, 03 May 2017 02:09:44 GMT
Connection: keep-alive
// 解析后的参数体
Request Body: {"name":"test"}%
详情可参见:https://github.com/dlau/koa-body/blob/master/examples/multipart.js
联合koa-router使用案例
通常情况下,最好只在需要时解析主体,如果使用支持中间件组合的路由器,则只能为某些路由注入主体。
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
const koaBody = require('koa-body');
router.post('/users', koaBody(),(ctx) => { // 获取参数体中的属性和值
console.log(`files:${util.inspect(ctx.request.body.fields)}; body:${util.inspect(ctx.request.body.files)}`);
ctx.body = ctx.request.body;
});
app.use(router.routes());
app.listen(3000);
// 请求示例和结果
console.log('curl -i http://localhost:3000/users -d "name=test"');
options参数
可用于koa-body的选项。4个自定义选项,其他都来自于raw-body和formidable。
- koa-body 参数
参数名 | 描述 | 类型 | 默认值 |
---|---|---|---|
patchNode | 将补丁写入ctx.req节点中 | Boolean | false |
patchKoa | 将补丁写入ctx.request节点中 | Boolean | true |
jsonLimit | JSON 数据体的大小限制 | String / Integer | 1mb |
formLimit | 限制表单请求体的大小 | String / Integer | 56kb |
textLimit | 限制 text body 的大小 | String / Integer | 56kb |
encoding | 表单的默认编码 | String | utf-8 |
multipart | 是否支持 multipart-formdate 的表单 | Boolean | false |
urlencoded | 是否支持 urlencoded 的表单 | Boolean | true |
text | 是否解析 text/plain 的表单 | Boolean | true |
json | 是否解析 json 请求体 | Boolean | true |
jsonStrict | 是否使用 json 严格模式,true 会只处理数组和对象 | Boolean | true |
formidable | 配置更多的关于 multipart 的选项 | Object | |
onError | 错误处理 | Function | |
stict | 严格模式,启用后不会解析 GET, HEAD, DELETE 请求 | Boolean | true |
- formidable 参数
参数名 | 描述 | 类型 | 默认值 |
---|---|---|---|
maxFields | 限制字段的数量 | Integer | 1000 |
maxFieldsSize | 限制字段的最大值 | Integer | 2mb (2 * 1024 * 1024) |
uploadDir | 设置文件上传的文件夹 | String | os.tmpDir() |
keepExtensions | 保留原来的文件后缀 | Boolean | false |
hash | 如果希望计算传入文件的校验,请将其设置为“sha1”或“md5” | String | false |
multipart | 是否支持多文件上传 | Boolean | true |
onFileBegin | 开始时对文件进行特殊回调。它可以用于在将文件保存到磁盘之前重命名文件等 | Function |
- formidable的onFileBegin
关于严格模式的说明
详情参见: http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-19#section-6.3
- GET、HEAD和DELETE请求对请求体没有定义语义,但这并不意味着它们在某些用例中无效。
- 缺省情况下,koa-body是严格模式
项目配置案例
const Koa = require('koa');
const bodyparse = require('koa-body');
const app = new Koa();
const path = require('path');
const util = require('util');
/**
* 解析请求体
* @links: https://github.com/dlau/koa-body
* 上送数据解析,包括post、get的参数,二进制文件(raw属性)传输等的自动解析到ctx.files和ctx.body中
*/
app.use(
bodyparse({
multipart: true, // 支持文件上传
formidable: {
uploadDir: path.join(__dirname, 'public/upload/'), // 设置文件上传目录
keepExtensions: true, // 保持文件的后缀
maxFieldsSize: 2 * 1024 * 1024, // 文件上传大小,缺省2M
onFileBegin: (name, file) => { // 文件上传前的设置
const fp = path.join(__dirname, 'public/upload/');
if (!fs.existsSync(fp)) { // 检查是否有“public/upload/”文件夹
fs.mkdirSync(fp); // 没有就创建
}
console.log(`bodyparse: name:${name}; file:${util.inspect(file)}`);
}
}
})
);
app.use(ctx => {
/* body中的信息,如下:
{
fields: { lessonid: '1', bookid: '1', folder: 'gxkt/audio', parse: '1' },
files: { audioData:
File {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
size: 47830,
path: 'E:\\Prj\\nuoya\\upload\\temp\\upload_066afb801e15d501aa2d7b144a394a57',
name: 'blob',
type: 'audio/wav',
hash: null,
lastModifiedDate: 2018-12-05T06:02:31.049Z,
_writeStream: [Object]
}
}
}
*/
console.log(`files:${util.inspect(ctx.request.body.fields)}; body:${util.inspect(ctx.request.body.files)}`);
ctx.body = ctx.request.body;
});
app.listen(3000);