eggjs 如何方便的獲取multipart 參數

eggjs 自身的multipart 解析

eggis 有兩大特色:node

  1. 懶解析:只有在主動調用時, 好比this.multipart, 纔會解析multipart 請求。
  2. 流式stream處理:若是想在拿到fd 文件前獲得fields, fd 就必須放在fields 以後。

Stream 能讓server 性能更好。可是這也給開發帶來了不便。es6

  1. 處理 fd 以前,不能提早得到fields
  2. fd stream 必須消費掉,不然鏈接不會關閉, 瀏覽器pending.

統一處理

能夠參考下面的方法,統一解析出 fields, 並消費掉stream.json

// app/core/base_controller.js
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);
    }

     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 在請求最後及時清理:app

if (ctx.files && ctx.files.length) {
    for (let file of ctx.files) {
      if (file.path && fs.existsSync(file.path)) {
        fs.unlinkSync(file.path)
      }
    }
  }

加載baseController

顯然,默認狀況下,node 不支持項目根目錄加載:async

require('core/base_controller')

咱們須要在app.js 裏面設置:NODE_PATH性能

let path = require('path')
process.env.NODE_PATH = path.resolve(__dirname, 'app/') ;
require('module').Module._initPaths();

或者在命令行直接設置: NODE_PATH=$PWD/app egg-bin devui

vscode 自動補全

vscode 可不知道你設置了NODE_PATH, 因此 vsc 也找不到module. 咱們須要再項目根目錄中經過jsconfig.json 告訴vsc 去base_dir 找module.this

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "baseUrl": "./app"
  },
  "exclude": [
    "node_modules"
  ]
}
相關文章
相關標籤/搜索