Multer 文件上传 — 头像与附件管理

知识库
知识库文档
/tech-stacks/express/examples/Multer 文件上传 — 头像与附件管理.md

文档

Express 文件上传 + 静态文件服务

目标

使用 Multer 处理单文件/多文件上传,同时提供静态文件访问,是毕设中「头像上传」「文件提交」的标配方案。

完整代码

// app.js
const express = require('express');
const multer = require('multer');
const path = require('path');
const crypto = require('crypto');

const app = express();

// ───── 配置 Multer ─────
const storage = multer.diskStorage({
  destination: (req, file, cb) => cb(null, 'uploads/'),
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname);
    const name = crypto.randomBytes(16).toString('hex');
    cb(null, `${name}${ext}`);
  },
});

const fileFilter = (req, file, cb) => {
  const allowed = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
  if (allowed.includes(file.mimetype)) {
    cb(null, true);
  } else {
    cb(new Error('仅支持 JPG/PNG/GIF/PDF 文件'), false);
  }
};

const upload = multer({ storage, fileFilter, limits: { fileSize: 5 * 1024 * 1024 } });

// ───── 静态文件服务 ─────
app.use('/uploads', express.static('uploads'));
app.use(express.static('public'));

// ───── API 路由 ─────

// 单文件上传(头像)
app.post('/api/upload/avatar', upload.single('avatar'), (req, res) => {
  if (!req.file) return res.status(400).json({ error: '请选择文件' });
  res.json({
    message: '上传成功',
    url: `/uploads/${req.file.filename}`,
    originalName: req.file.originalname,
    size: req.file.size,
  });
});

// 多文件上传(论文附件)
app.post('/api/upload/attachments', upload.array('files', 10), (req, res) => {
  if (!req.files || req.files.length === 0) {
    return res.status(400).json({ error: '请选择文件' });
  }
  const uploaded = req.files.map(f => ({
    url: `/uploads/${f.filename}`,
    name: f.originalname,
    size: f.size,
  }));
  res.json({ message: `成功上传 ${uploaded.length} 个文件`, files: uploaded });
});

// 错误处理
app.use((err, req, res, next) => {
  if (err instanceof multer.MulterError) {
    if (err.code === 'LIMIT_FILE_SIZE') {
      return res.status(400).json({ error: '文件大小不能超过 5MB' });
    }
    return res.status(400).json({ error: err.message });
  }
  res.status(500).json({ error: err.message });
});

app.listen(3000, () => console.log('📁 http://localhost:3000'));

配套 HTML 测试页面

<!-- public/index.html -->
<h2>头像上传</h2>
<form id="avatarForm">
  <input type="file" name="avatar" accept="image/*">
  <button type="submit">上传头像</button>
</form>
<img id="preview" src="" style="max-width:200px;display:none;">

<h2>附件上传(多选)</h2>
<form id="filesForm">
  <input type="file" name="files" multiple>
  <button type="submit">上传附件</button>
</form>
<div id="fileList"></div>

<script>
  document.getElementById('avatarForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    const res = await fetch('/api/upload/avatar', { method: 'POST', body: fd });
    const data = await res.json();
    document.getElementById('preview').src = data.url;
    document.getElementById('preview').style.display = 'block';
  });

  document.getElementById('filesForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    const fd = new FormData(e.target);
    const res = await fetch('/api/upload/attachments', { method: 'POST', body: fd });
    const data = await res.json();
    document.getElementById('fileList').innerHTML = data.files
      .map(f => `<p><a href="${f.url}">${f.name}</a> (${(f.size/1024).toFixed(1)}KB)</p>`)
      .join('');
  });
</script>

运行

mkdir uploads public
npm install express multer
node app.js

信息

路径
/tech-stacks/express/examples/Multer 文件上传 — 头像与附件管理.md
更新时间
2026/5/30