You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Multer在Express.js中实现图片上传时的问题排查

Express.js + Multer 图片上传异常问题排查与修复

问题现象

  • 上传.jpg或.png文件时,文件无法上传,页面提示「Error: Images Only!」
  • 未选择文件点击上传时,页面无法显示预期的「No file selected!」提示

已尝试操作

  • 检查过checkFileType函数的文件类型/扩展名校验逻辑
  • 确认表单已设置enctype="multipart/form-data"

现有代码

后端Express代码

const express = require('express');
const multer = require('multer');
const path = require('path');

const app = express();

// 设置存储引擎
const storage = multer.diskStorage({
  destination: './uploads/',
  filename: function(req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
  }
});

// 初始化上传配置
const upload = multer({
  storage: storage,
  limits: { fileSize: 1000000 },
  fileFilter: function(req, file, cb) {
    checkFileType(file, cb);
  }
}).single('myImage');

// 文件类型校验函数
function checkFileType(file, cb) {
  // 允许的扩展名
  const filetypes = /jpeg|jpg|png|gif/;
  // 检查扩展名
  const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
  // 检查MIME类型
  const mimetype = filetypes.test(file.mimetype);

  if (mimetype && extname) {
    return cb(null, true);
  } else {
    cb('Error: Images Only!');
  }
}

// 静态文件目录
app.use(express.static('./public'));

// 上传路由
app.post('/upload', (req, res) => {
  upload(req, res, (err) => {
    if (err) {
      res.render('index', {
        msg: err
      });
    } else {
      if (req.file == undefined) {
        res.render('index', {
          msg: 'No file selected!'
        });
      } else {
        res.render('index', {
          msg: 'File uploaded!',
          file: `uploads/${req.file.filename}`
        });
      }
    }
  });
});

// 启动服务器
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));

前端模板文件(index.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Image Upload</title>
</head>
<body>
  <h1>Upload an Image</h1>
  <form action="/upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="myImage">
    <input type="submit" value="Upload">
  </form>
  <% if (typeof msg != 'undefined') { %>
    <p><%= msg %></p>
  <% } %>
  <% if (typeof file != 'undefined') { %>
    <img src="<%= file %>" alt="Uploaded Image">
  <% } %>
</body>
</html>

问题原因与修复方案

1. 合法图片被拦截(提示「Error: Images Only!」)

原因:
原校验逻辑的正则匹配不严谨,MIME类型仅匹配子串,可能无法覆盖所有合法图片的MIME类型(如部分浏览器识别.jpg文件的MIME类型为image/jpg,虽然原正则能匹配,但边缘场景下仍可能失效),同时校验逻辑没有容错空间。

修复方案:
修改checkFileType函数,改用数组匹配更严谨的扩展名和MIME类型:

function checkFileType(file, cb) {
  // 明确允许的扩展名和MIME类型
  const allowedExts = ['.jpeg', '.jpg', '.png', '.gif'];
  const allowedMimes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
  
  const fileExt = path.extname(file.originalname).toLowerCase();
  const fileMime = file.mimetype.toLowerCase();

  if (allowedExts.includes(fileExt) && allowedMimes.includes(fileMime)) {
    return cb(null, true);
  } else {
    cb('Error: Images Only!');
  }
}

2. 未选择文件时不显示提示

原因:

  • 未配置模板引擎,且视图文件使用.html后缀,但包含EJS模板语法(<% %>),Node.js无法解析渲染;
  • 未指定视图文件目录,res.render无法找到对应模板文件。

修复方案:

  1. 安装EJS模板引擎:
npm install ejs --save
  1. 在Express代码中添加模板引擎配置:
// 配置EJS为模板引擎
app.set('view engine', 'ejs');
// 指定视图文件存放目录(需手动创建views文件夹)
app.set('views', path.join(__dirname, 'views'));
  1. 将index.html重命名为index.ejs,并移动到项目根目录的views文件夹下;
  2. 手动创建uploads目录(multer不会自动生成上传目录,否则会导致文件写入失败)。

内容的提问来源于stack exchange,提问作者Aminul Islam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 19:14:54