使用Express处理表单中的文件上传的方法

156 阅读2分钟

如何管理存储和处理通过表格上传的文件,在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" ,否则文件不会被上传

当用户按下提交按钮时,浏览器会自动向页面上同一来源的POST ,并向/submit-form URL发出请求。浏览器发送所包含的数据,不是作为普通表单的编码application/x-www-form-urlencoded ,而是作为multipart/form-data

在服务器端,处理多部分数据可能很棘手,而且容易出错,所以我们要使用一个叫做formidable的实用库。这里是GitHub repo,它有超过4000颗星,并且维护良好。

你可以用它来安装。

然后在你的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)
    })
    //...
})