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);
相关推荐
FungLeo3 小时前
成为全栈·Node 后端篇·阅读量防刷:去重、冷却与计数写分离
node.js·读写分离·数据去重·接口防刷·成为全栈·数据冷却
CharlesYu014 小时前
前端性能优化的第一性原理,是不断缩短“用户发起意图 → 获得可用结果”之间的时间
前端
平头哥技术团队5 小时前
Day 21 _ 页内锚点_给每段起个 id,目录写 href=_#id_,点一下页面就滚到那一段
前端·html·html5
子兮曰6 小时前
Bun v1.4.1 深度解析:从 Zig 到 Rust,一场 11 天、64 个 AI 代理的语言迁徙
前端·后端·bun
人民广场吃泡面6 小时前
什么是AI Agent?它又能给前端带来哪些效率提升?
前端·人工智能
中科三方6 小时前
两家域名注册商资质被ICANN终止:企业域名资产安全再受关注
前端·网络·安全·域名
bug总结7 小时前
uniapp vue3全局方法注册使用
前端·javascript·uni-app
华无丽言7 小时前
如何在宜搭中实现获取子表中的字段值赋值到父表中?
前端·javascript·低代码
IT_陈寒8 小时前
Vue的computed属性竟然坑了我一把
前端·人工智能·后端
威斯软科的老司机8 小时前
通俗讲解 CNN 图像识别、向量 Embedding、Softmax 概率计算这三块的简化原理
前端·人工智能·ui·数字孪生