egg 怎么在处理文件前,提前获取到multipart 请求的fields?

Created on 17 Jul 2018  ·  7Comments  ·  Source: eggjs/egg

按照文档,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')
})

```

  • Node Version: 10.0.0
  • Egg Version: 4.7.1
  • Plugin Name:
  • Plugin Version:
  • Platform: MacOSX 10.12
  • Mini Showcase Repository:

Most helpful comment

由于我不想流式处理,就简单地封装了一下:

     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)
      }
    }
  }

All 7 comments

Translation of this issue:


egg How to get the fields to the multipart request correctly

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')
    })

```

  • Node Version: 10.0.0
  • Egg Version: 4.7.1
  • Plugin Name:
  • Plugin Version:
  • Platform: MacOSX 10.12
  • Mini Showcase Repository:

看文档 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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kkys4bfgp75be9p picture kkys4bfgp75be9p  ·  36Comments

fengmk2 picture fengmk2  ·  51Comments

killagu picture killagu  ·  48Comments

atian25 picture atian25  ·  68Comments

popomore picture popomore  ·  38Comments