Express 如何使用 multer 文件上传?

Nest 的文件上传是基于 Express 的中间件 multer 实现的,在学习 Nest 文件上传之前,先学习下 multer 包的使用

新建一个文件夹

cors 包是处理跨域 header

index.js

javascript 复制代码
const express = require('express')
const multer  = require('multer')
const cors = require('cors');

const app = express()
app.use(cors());

const upload = multer({ dest: 'uploads/' })

app.post('/aaa', upload.single('aaa'), function (req, res, next) {
  console.log('req.file', req.file);
  console.log('req.body', req.body);
})

app.listen(3000);

新建 index.html

通过 FormData + axios 上传文件,指定内容的传输格式 content-type 为 multipart/form-data。

(axios 会自动根据内容指定 content-type,不需要手动指定)

xml 复制代码
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
  </head>
  <body>
    <input id="fileInput" type="file" />
    <script>
      const fileInput = document.querySelector("#fileInput");

      async function formData() {
        const data = new FormData();
        data.set("name", "fuhao");
        data.set("age", 18);
        data.set("aaa", fileInput.files[0]);

        const res = await axios.post("http://localhost:3000/aaa", data);
        console.log(res);
      }

      fileInput.onchange = formData;
    </script>
  </body>
</html>

用 node 把 server 跑起来,并且用 http-server 把静态服务跑起来

上传文件

这就是 form-data 的传输格式

服务端看下

req.file 拿到文件字段,非文件字段在 req.body

服务端多了 uploads 目录,下面保存着上传文件

这是单文件 上传 那多文件上传呢?

index.js 添加 /bbb

javascript 复制代码
const express = require('express')
const multer  = require('multer')
const cors = require('cors');

const app = express()
app.use(cors());

const upload = multer({ dest: 'uploads/' })

app.post('/aaa', upload.single('aaa'), function (req, res, next) {
  console.log('req.file', req.file);
  console.log('req.body', req.body);
})

app.post('/bbb', upload.array('bbb', 2), function (req, res, next) {
  console.log('req.files', req.files);
  console.log('req.body', req.body);
})

app.listen(3000);

index.html 支持多文件

xml 复制代码
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
  </head>
  <body>
    <input id="fileInput" type="file" multiple />
    <script>
      const fileInput = document.querySelector("#fileInput");

      async function formData2() {
        const data = new FormData();
        data.set("name", "fuhao");
        data.set("age", 20);
        [...fileInput.files].forEach((item) => {
          data.append("bbb", item);
        });

        const res = await axios.post("http://localhost:3000/bbb", data);
        console.log(res);
      }

      fileInput.onchange = formData2;
    </script>
  </body>
</html>

如果超过 2个文件 就会默认报错

改一下这个 错误

lua 复制代码
app.post('/bbb', upload.array('bbb', 2), function (req, res, next) {
    console.log('req.files', req.files);
    console.log('req.body', req.body);
}, function(err, req, res, next) {
    if(err instanceof multer.MulterError && err.code === 'LIMIT_UNEXPECTED_FILE') {
        res.status(400).end('Too many files uploaded');
    }
})

更复杂一点的情况,如果多个字段都会上传文件,而且限制也都不同呢?

index.js 更新

less 复制代码
app.post('/ccc', upload.fields([
    { name: 'aaa', maxCount: 3 },
    { name: 'bbb', maxCount: 2 }
]), function (req, res, next) {
    console.log('req.files', req.files);
    console.log('req.body', req.body);
})

index.html 更新

ini 复制代码
      async function formData3() {
        const data = new FormData();
        data.set("name", "fuhao");
        data.set("age", 20);
        data.append("aaa", fileInput.files[0]);
        data.append("aaa", fileInput.files[1]);
        data.append("bbb", fileInput.files[2]);
        data.append("bbb", fileInput.files[3]);

        const res = await axios.post("http://localhost:3000/ccc", data);
        console.log(res);
      }

      fileInput.onchange = formData3;

如何修改保存的文件名?

javascript 复制代码
const express = require('express')
const multer  = require('multer')
const cors = require('cors');
const path = require('path')

const app = express()
app.use(cors());

const storage = multer.diskStorage({
  destination(req, file, cb) {
    cb(null, 'uploads/')
  },
  filename(req, file, cb) {
    // 原始文件名
    const ext = path.extname(file.originalname)
    const name = path.basename(file.originalname, ext)

    // 自定义规则
    const newName = `${name}-${Date.now()}${ext}`

    cb(null, newName)
  }
})

const upload = multer({ storage })

app.post('/aaa', upload.single('aaa'), function (req, res, next) {
  console.log('req.file', req.file);
  console.log('req.body', req.body);
})

app.post('/bbb', upload.array('bbb', 2), function (req, res, next) {
    console.log('req.files', req.files);
    console.log('req.body', req.body);
}, function(err, req, res, next) {
    if(err instanceof multer.MulterError && err.code === 'LIMIT_UNEXPECTED_FILE') {
        res.status(400).end('Too many files uploaded');
    }
})

app.post('/ccc', upload.fields([
    { name: 'aaa', maxCount: 3 },
    { name: 'bbb', maxCount: 2 }
]), function (req, res, next) {
    console.log('req.files', req.files);
    console.log('req.body', req.body);
})


app.listen(3000);
相关推荐
Pedantic1 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆1 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆2 小时前
VSCode自动格式化三要素
前端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen4 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518136 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode6 小时前
Redis 在生产项目的使用
前端·后端