簡體   English   中英

強大:解析多部分/表單數據請求,然后上傳文件

[英]Formidable: Parse multipart/form-data request THEN upload file

從昨天開始,我的 node express 應用程序出現了問題。

我想做的是下一個:

中間件 1,步驟 1(解析請求):使用 formidable 解析 req.body 中的 multipart/form-data 並執行我想對數據執行的操作(例如驗證),如果一切正常,則 go 到步驟 2。

中間件2,第2步(上傳文件):使用formidable上傳文件(已解析)

問題:

  • Multer:已經用 Multer 測試過但不可能,我必須將中間件 2 放在中間件 1 之前,否則 req.body 為空(也測試了 multer.none())。
  • Formidable:用 formidable 積極測試,但是當我在中間件 1 中解析請求時,formidable 不會在中間件 2 中做任何事情(因為我的 req.body 已經解析了,他沒有找到文件?)

我知道有一個過濾器 function 但我真的想要兩個獨立的中間件。

快遞中間件

const formidable = require('formidable');

// parse request
module.exports.middleware1 = async (req, res, next) => {
  const form = formidable({ multiples: true });

  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }
    
    // request parsed
    // do what I want to do with the fields (such validation)
    console.log(fields)
    
    next()
  });
}

// upload file
module.exports.middleware2 = async (req, res, next) => {
  const options = {
    uploadDir: 'test',
    keepExtensions: true,
    maxFiles: 1,
    filename: function (name, ext, part, form) {
      return name
    },
    filter: function ({name, originalFilename, mimetype}) {
      return true
    }
  }
  const form = formidable(options);
  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }
    
    // file uploaded, go to controller
    
    next()
  });
}

前端應用

publishPost: function () {
  let formData = new FormData()

  const post = {
    filters: {
      ...this.postFilters
    },
    details: {
      ...this.postDetails
    }
  }

  formData.append('post', JSON.stringify(post))
  formData.append('file', this.postMedia.file)

  postService.createOne(formData).then((res) => {
    if (res) {
      postServiceStatus.createOneDone()
    }
  });
}

如果有人有想法,我將不勝感激!

我終於找到了解決問題的方法!

我創建了一個全局錯誤處理程序來處理我的 API 上的所有錯誤,當錯誤與我創建文件的路徑相關時(在第一個中間件中),我刪除了包含在 req.file 中傳遞的信息的文件。

const fs = require('fs')
const { DEFAULT_API_PATH } = process.env

/**
 * Handle middlewares errors
 * @param {Object} err error object
 * @param {String} err.type type of error (service affected by the error)
 * @param {String} err.error original error
 * @param {String} err.message returned error
 * @param {Number} err.status error status
 * @returns 
 */
module.exports = async (err, req, res, next) => {
  if (err.error) console.log(err.error) 
  
  // Delete file
  if (req.path === `${DEFAULT_API_PATH}/posts/create` && req.file) {
    if (fs.existsSync(req.file.path)) {
      fs.unlinkSync(req.file.path, function (err) {
        console.log(err)
      }); 
    }
  } 
  
  if (err.type && err.type === 'database') return res.status(err.status || 400).send({ error: err.message || 'Une erreur innatendue s\'est produite avec la base de données. Veuillez réessayer dans un instant.' }) 
  else if (err.type && err.type === 'server') return res.status(err.status || 400).send({ error: err.message || 'Une erreur innatendue s\'est produite avec le serveur. Veuillez réessayer dans un instant.' }) 
  
  return res.status(err.status || 400).send({ error: err.message || 'Une erreur innatendue s\'est produite. Veuillez réessayer dans un instant.' }) 
}

服務器只能使用一次傳入請求,因為請求正文由客戶端流式傳輸,並且 HTTP 協議不允許服務器向客戶端請求“倒帶”。

multerformidable的想法是在使用請求時將文件寫入uploadDir 如果您不想在第一個中間件中執行此操作,則需要將文件存儲在 Javascript 變量(例如res.locals.uploadedFile )中,然后在第二個中間件中自行將其寫入uploadDir 但是這樣做有什么好處呢? 主要 memory 比磁盤空間更昂貴。

為什么你堅持使用兩個獨立的中間件?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM