如何在Express中管理存儲和處理通過表單上傳的文件

這是一個允許用戶上傳文件的HTML表單的示例:

<form method="POST" action="/submit-form" enctype="multipart/form-data">
 <input type="file" name="document" />
 <input type="submit" />
</form>

不要忘記在表單中添加enctype="multipart/form-data",否則文件將無法被上傳

當用戶點擊提交按鈕時,瀏覽器會自動向與該頁面相同源頭的/submit-form URL 發送一個POST請求。瀏覽器將數據以multipart/form-data的形式而不是編碼的形式(即普通表單的application/x-www-form-urlencoded)發送出去。

在服務器端,處理multipart數據可能會很棘手且容易出錯,因此我們將使用一個名為formidable的實用庫。這是GitHub倉庫,它擁有超過4000顆星且得到良好的維護。

您可以使用以下命令來安裝它:

npm install formidable

然後在您的Node.js文件中引入它:

const express = require('express')
const app = express()
const formidable = require('formidable')

現在,在/submit-form路由的POST端點中,我們使用formidable.IncomingForm()實例化一個新的Formidable表單:

app.post('/submit-form', (req, res) => {
 new formidable.IncomingForm()
})

在這樣做之後,我們需要能夠解析表單。我們可以通過提供一個回調函數來同步進行解析,這意味著所有文件都被處理,一旦formidable完成它們的處理,它就會使它們可用:

app.post('/submit-form', (req, res) => {
 new formidable.IncomingForm().parse(req, (err, fields, files) => {
 if (err) {
 console.error('Error', err)
 throw err
 }
 console.log('Fields', fields)
 console.log('Files', files)
 for (const file of Object.entries(files)) {
 console.log(file)
 }
 })
})

或者,您可以使用事件而不是回調函數。例如,當每個文件被解析時,或者其他事件(如文件處理完成、接收到非文件字段、或者出現錯誤)發生時,您可以收到通知:

app.post('/submit-form', (req, res) => {
 new formidable.IncomingForm().parse(req)
 .on('field', (name, field) => {
 console.log('Field', name, field)
 })
 .on('file', (name, file) => {
 console.log('Uploaded file', name, file)
 })
 .on('aborted', () => {
 console.error('Request aborted by the user')
 })
 .on('error', (err) => {
 console.error('Error', err)
 throw err
 })
 .on('end', () => {
 res.end()
 })
})

無論您選擇哪種方式,您將獲得一個或多個Formidable.File對象,這些對象提供有關上傳的文件的信息。這是一些您可以調用的方法:

  • file.size,文件大小(以字節為單位)
  • file.path,文件寫入的路徑
  • file.name,文件的名稱
  • file.type,文件的MIME類型

路徑默認為臨時文件夾,如果您侦聽fileBegin事件,可以修改它:

app.post('/submit-form', (req, res) => {
 new formidable.IncomingForm().parse(req)
 .on('fileBegin', (name, file) => {
 file.path = __dirname + '/uploads/' + file.name
 })
 .on('file', (name, file) => {
 console.log('Uploaded file', name, file)
 })
 //...
})