按照文档,egg对multipart 请求只能是流式处理,文件需要放到最后。
不知道有什么好办法 提前获取到multipart 请求的fields?
const sendToWormhole = require('stream-wormhole');
const parts = this.ctx.multipart({ autoFields: true });
while ((part= await parts()) != null) {
if(!part.length){
await sendToWormhole(part);//需要先处理了文件,才能拿到全部的field。
}
}
fields = parts.field;
koa-better-body 使用起来就很simple, egg 可以在处理文件前直接获取到fields 吗?
```
var body = require('koa-better-body')
var app = koa()
app
.use(body())
.use(function * () {
console.log(this.request.body) // if buffer or text
console.log(this.request.files) // if multipart
console.log(this.request.fields) // if json or _POST
console.log(this.request.query)
}).listen(8080, function () {
console.log('koa server start listening on port 8080')
})
```
Translation of this issue:
I looked at the documentation, divided into individual files, and multiple files. I tried a lot of methods and didn't find out how to get the fields correctly.
Looks like egg-multiparts is too complicated, koa-better-body is very simple to use:
```
Var body = require('koa-better-body')
Var app = koa()
App
.use(body())
.use(function * () {
Console.log(this.request.body) // if buffer or text
Console.log(this.request.files) // if multipart
Console.log(this.request.fields) // if json or _POST
Console.log(this.request.query)
}).listen(8080, function () {
Console.log('koa server start listening on port 8080')
})
```
看文档 https://eggjs.org/zh-cn/basics/controller.html#%E8%8E%B7%E5%8F%96%E4%B8%8A%E4%BC%A0%E7%9A%84%E6%96%87%E4%BB%B6
由于我不想流式处理,就简单地封装了一下:
async multipart() {
const tmp = require('tmp')
const fs = require('fs')
const ctx = this.ctx
const files = [];
ctx.files = files
let fields, part;
if (this.ctx.get('Content-Type').startsWith('multipart/')) {
try {
// const file = await ctx.getFileStream()
// files.push(file);
// fields = stream.fields;
// const sendToWormhole = require('stream-wormhole');
// let result = await ctx.oss.put('egg-multipart-test/' + part.filename, part);
// await sendToWormhole(part);
const parts = ctx.multipart({ autoFields: true });
while ((part = await parts()) != null) {
if (part.length) {
} else if (part.filename) {
const tmpFile = tmp.fileSync({prefix: 'eggjs-upload-'})
const ws = fs.createWriteStream(null, {fd:tmpFile.fd})
part.pipe(ws)
part.path = tmpFile.name
part.fd = tmpFile.fd
files.push(part)
}
}
fields = parts.field
} catch (err) {
//await sendToWormhole(part);
throw err;
}
}
return [files, fields];
}
使用时,直接可获取到上传的文件+fields:
const [files, fields] = await this.multipart();
另外为了及时清理临时文件,我设置了 ctx.files 存放临时文件。
然后通过中间件middleware 在请求最后及时清理:
if (ctx.files && ctx.files.length) {
for (let file of ctx.files) {
if (file.path && fs.existsSync(file.path)) {
fs.unlinkSync(file.path)
}
}
}
@ahuigo 在自定义control类封装multipart后,while无法循环,还需要其他配置?
@Currencywy 我更新了一下代码。流式处理后,就不能再获取数据了。while 当然不行。
所以我这个 multipart() 把files/fields 一并返回了
我昨天更新了代码,你试了吗?我的代码逻辑没问题吧。
while ((part = await parts()) != null) 只要保证每个part 被消费掉,就没问题啊。要是这个都有问题,提issue
@ahuigo 刚试了,是调用this.multipart()是忘记写 await
Most helpful comment
由于我不想流式处理,就简单地封装了一下:
使用时,直接可获取到上传的文件+fields:
另外为了及时清理临时文件,我设置了
ctx.files存放临时文件。然后通过中间件middleware 在请求最后及时清理: