eggjs 如何获取multipart 参数

1,347 阅读1分钟

eggjs 自身的multipart 解析

eggis 有两大特点:

  1. 懒解析:只有在主动调用时, 比如this.multipart, 才会解析multipart 请求。
  2. 流式stream处理:如果想再拿到fd 文件前得到fields, fd 就必须放在fields 之后。

这可能是出于性能和安全的考虑吧。但是这也给开发带来了不便。

  1. 处理 fd 之前,不能提前获得fields
  2. fd stream 必须消费掉,否则连接不会关闭, 浏览器pending.

统一处理

可以参考下面的方法,统一解析出 fields, 并消费掉stream.

// app/core/base_controller.js
// app/core/base_controller.js
const tmp = require('tmp')
const fs = require('fs')
const app = require('egg');

module.exports =
  app.BaseController =
  class BaseController extends app.Controller {
    rest(rest) {
      this.ctx.body = typeof rest === 'object' ? rest : JSON.stringify(rest)
      this.ctx.type = 'application/json';
    }

    throw(msg) {
      msg = msg || 'unknown';
      this.ctx.throw(400, msg);
    }

    buildURLQuery(obj){
      return Object.entries(obj)
            .map(pair => pair.map(encodeURIComponent).join('='))
            .join('&');
    }


    async multipart() {
      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');
          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)
              //let result = await ctx.oss.put('egg-multipart-test/' + part.filename, part);
              //await sendToWormhole(part);
            }
          }
          fields = parts.field
        } catch (err) {
          //await sendToWormhole(part);
          throw err;
        }
      }
      return [files, fields];
    }
  }