Express 文件上传 multer - 就像前端的 el-upload

0 阅读3分钟

1. 先说前端的文件上传

你有没有用过 Element Plus 的 el-upload?

<el-upload
  action="/api/upload"
  :auto-upload="false"
  :on-change="handleChange"
>
  <el-button>选择文件</el-button>
</el-upload>

点击按钮 → 选中文件 → 自动上传。

这背后原理是啥?

就是 FormData + axios 发送到后端!

const data = new FormData();
data.set('file', file对象);

axios.post('/api/upload', data);

2. 后端怎么接收?用 multer!

multer 就是 Express 专门用来处理文件上传的中间件。

安装

npm install express multer cors

基础用法

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('/upload', upload.single('file'), (req, res) => {
  console.log('文件信息:', req.file);   // 文件详情
  console.log('其他字段:', req.body);   // 其他表单字段
  res.send('上传成功');
});

app.listen(3333);

关键点

  • upload.single('file') - 接收字段名为 file 的单个文件
  • req.file - 获取上传的文件信息
  • req.body - 获取其他非文件字段

3. 前端怎么传?

<input type="file" id="fileInput" />

<script>
const fileInput = document.querySelector('#fileInput');

fileInput.onchange = async () => {
  const data = new FormData();
  data.set('file', fileInput.files[0]);

  const res = await axios.post('http://localhost:3333/upload', data);
  console.log(res.data);
};
</script>

对比 Element Plus el-upload

// el-upload 内部就是这样干的
const data = new FormData();
data.append('file', file.raw);
axios.post('/api/upload', data);

4. 多文件上传

场景:一次传多个文件

// 后端 - 最多传 2 个文件
app.post('/upload-multiple', upload.array('files', 2), (req, res) => {
  console.log('文件列表:', req.files);  // 数组形式
  res.send('上传成功');
});

前端

<input type="file" id="fileInput" multiple />

fileInput.onchange = async () => {
  const data = new FormData();
  // 多个文件用 append 追加
  [...fileInput.files].forEach(file => {
    data.append('files', file);
  });

  await axios.post('http://localhost:3333/upload-multiple', data);
};

对比 el-upload

<el-upload
  :auto-upload="false"
  :file-list="fileList"
  multiple
>
</el-upload>

5. 不同字段传不同文件

场景:头像 + 附件分开传

// 后端
app.post('/upload-fields', upload.fields([
  { name: 'avatar', maxCount: 1 },    // 头像,最多1个
  { name: 'attachments', maxCount: 3 } // 附件,最多3个
]), (req, res) => {
  console.log('头像:', req.files['avatar']);
  console.log('附件:', req.files['attachments']);
  res.send('上传成功');
});

前端

const data = new FormData();
data.append('avatar', avatarFile);        // 头像
data.append('attachments', file1);        // 附件1
data.append('attachments', file2);        // 附件2

await axios.post('http://localhost:3333/upload-fields', data);

对比 el-upload

<el-upload
  action="/api/upload"
  :auto-upload="false"
  :file-list="fileList"
>
  <el-button>上传头像和附件</el-button>
</el-upload>

6. 错误处理

传的文件超过限制怎么办?

app.post('/upload-multiple', upload.array('files', 2),
  (req, res) => {
    res.send('上传成功');
  },
  // 错误处理中间件
  (err, req, res, next) => {
    if (err instanceof multer.MulterError) {
      if (err.code === 'LIMIT_FILE_SIZE') {
        res.status(400).send('文件太大');
      } else if (err.code === 'LIMIT_UNEXPECTED_FILE') {
        res.status(400).send('文件数量超限');
      }
    } else {
      res.status(500).send('服务器错误');
    }
  }
);

7. 自定义文件名和保存路径

默认会生成随机文件名,想自定义?

const path = require('path');

const storage = multer.diskStorage({
  // 保存目录
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  // 文件名
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname); // 扩展名
    const name = Date.now() + '-' + Math.random().toString(36).substr(2, 9);
    cb(null, name + ext);
  }
});

const upload = multer({ storage });

对比前端的 URL.createObjectURL

// 前端预览本地图片
const url = URL.createObjectURL(file);
img.src = url;

8. 完整流程图

前端                                后端
 ───                                ───
FormData + axios    ──────────►   Express + multer
     │                                    │
     │   multipart/form-data             │
     │   (文件分割传输格式)               │
     │                                    │
     │                               req.files
     │                                    ▼
     │                              保存到磁盘
     │                                    │
     ◄────────────────────────────────────┘
   响应

9. 总结

multer 方法作用对比前端
upload.single('field')单文件上传el-upload 单文件
upload.array('field', n)多文件上传el-upload multiple
upload.fields([...])多字段多文件-
upload.any()任意文件-
multer.diskStorage()自定义存储URL.createObjectURL

一句话总结

multer 就是 Express 的文件上传中间件,类似于前端的 el-upload 组件帮你搞定文件上传。

后端接收文件 = multer 前端上传文件 = FormData + axios / el-upload


看完还不懂?评论区见!

觉得有帮助,点个赞再走~ 👋