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

为什么服务器在Postman中正常,前端上传文件却异常?

问题:Express + Multer 文件上传服务器在React前端上传非法文件时响应异常

我用Express和Multer搭建了文件上传服务器,搭配React前端实现文件提交功能。上传PDF格式的book文件和图片格式的coverImage文件时服务器运行正常,但上传不符合要求的文件类型时,服务器有时返回错误响应,有时无响应。奇怪的是,使用Postman测试时服务器始终运行正常。

服务器代码

const express = require("express");
const multer = require("multer");
const cors = require("cors");
const app = express();
app.use(cors());

//----------------------------------------
const fileStorage = multer.diskStorage({
  destination: function (req, file, cb) {
    const fileType = file.fieldname === "coverImage" ? "images" : "books";
    cb(null, fileType); // 根据文件类型指定目标目录
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname); // 使用原始文件名
  },
});

const validateFileTypes = (req, file, cb) => {
  if (file.fieldname === "book" && !file.originalname.endsWith(".pdf")) {
    return cb(new Error('Only PDF files are allowed for the "book" field'));
  }

  if (file.fieldname === "coverImage" && !file.mimetype.startsWith("image/")) {
    return cb(
      new Error('Only image files are allowed for the "bookCover" field')
    );
  }

  // 接受文件
  cb(null, true);
};
app.use(
  multer({ storage: fileStorage, fileFilter: validateFileTypes }).fields([
    { name: "book", maxCount: 1 }, // 'images'字段最多两个文件
    { name: "coverImage", maxCount: 1 }, // 'documents'字段最多三个文件
  ])
);

//--------------------------------------

app.post("/", (req, res) => {
  res.status(200).json({ status: "success", msg: "It's working!" });
});

// app.post("/upload", (req, res, next)=>{

//   console.log(req.files);
//   console.log(req.body);
//   res.status(200).json({msg: "Files Uploaded Successfully!"});

// })

app.all("*", (req, res, next) => {
  // res.status(400).json({error: `Can't find the root you are looking for my love: ${req.url}`})
  const err = new Error(`Can't find the root ${req.url} my love`);
  err.status = "fail";
  err.statusCode = 404;
  next(err);
});

app.use((err, req, res, next) => {
  err.status = err.status || "error";
  err.statusCode = err.statusCode || 500;

  res.status(err.statusCode).json({ status: err.status, message: err.message });

  next();
});

app.listen(4000);

前端代码

import { useState, useRef } from "react"

export default function TestPage(){
    const [messageState, setMessageState] = useState({});

    const bookRef = useRef();
    const coverImageRef = useRef();

    
    const submitHandler = (event)=>{
        event.preventDefault();
        const fileData = new FormData();
        fileData.append('book', bookRef.current.files[0]);
        fileData.append('coverImage', coverImageRef.current.files[0]);
        sendFile(fileData);
    }

    const sendFile= async (fileData) => {
        try {
          const response = await fetch("http://localhost:4000/", {
            method: "POST",
            body: fileData,
          });
      
          if (!response.ok) {
            // 如果响应状态不正常,抛出错误
            const errorResponse = await response.json();
            const errorMessage = errorResponse.message || "Server error occurred";
            throw new Error(`HTTP error! Status: ${response.status}. Error message: ${errorMessage}`);
          }
      
          const responseData = await response.json();
          setMessageState(responseData);
          // 需要的话在这里处理成功逻辑
        } catch (error) {
          // 处理fetch过程中出现的错误
          setMessageState(error.message);
          // 向用户展示服务器返回的错误信息或执行其他操作
        //   alert(`Server Error: ${error.message}`);
        }
      };
      
      

    return (
        <>
        
            <form onSubmit={submitHandler}>

                <input type="file" ref={bookRef} />
                <input type="file" ref={coverImageRef} />
                <button type="submit">Submit</button>
            </form>
            <h1>Message: {JSON.stringify(messageState)}</h1>
            {/* {messageState.map(item => <h1 key={item}>{item}</h1>)} */}
        </>
    )
}

问题原因及修复方案

核心问题分析

  1. Multer全局挂载引发的错误处理异常:你通过app.use()全局挂载了Multer中间件,这意味着所有请求(包括不需要文件上传的404请求)都会经过Multer处理。当非法文件触发fileFilter错误时,错误传递到全局处理器后,可能因为请求体未完全解析导致响应卡住。
  2. 前端未处理空文件场景:用户未选择文件就提交时,files[0]为undefined,FormData会将其转为字符串"undefined",导致Multer处理逻辑异常。
  3. 错误处理器多余的next()调用:全局错误处理器最后调用next(),会让Express继续寻找后续中间件,导致响应无法正常结束。

修复步骤

1. 将Multer中间件绑定到指定上传路由

移除全局的app.use(multer(...)),只在需要文件上传的路由(比如/upload)上使用:

// 删除原来的app.use(multer(...))代码
// 改为在/upload路由中挂载Multer
app.post("/upload", 
  multer({ storage: fileStorage, fileFilter: validateFileTypes }).fields([
    { name: "book", maxCount: 1 },
    { name: "coverImage", maxCount: 1 },
  ]), 
  (req, res, next)=>{
    console.log(req.files);
    console.log(req.body);
    res.status(200).json({msg: "文件上传成功!"});
  }
);

同时修改前端请求URL为http://localhost:4000/upload。

2. 前端增加空文件校验

提交前检查用户是否选择了所有必填文件,避免传递无效值:

const submitHandler = (event)=>{
    event.preventDefault();
    const bookFile = bookRef.current.files?.[0];
    const coverImageFile = coverImageRef.current.files?.[0];
    
    if (!bookFile || !coverImageFile) {
        setMessageState("请选择所有必填文件");
        return;
    }
    
    const fileData = new FormData();
    fileData.append('book', bookFile);
    fileData.append('coverImage', coverImageFile);
    sendFile(fileData);
}

3. 修复全局错误处理器

移除错误处理器最后的next(),确保响应正常结束:

app.use((err, req, res, next) => {
  err.status = err.status || "error";
  err.statusCode = err.statusCode || 500;

  res.status(err.statusCode).json({ status: err.status, message: err.message });
  // 删除这里的next()调用
});

4. 优化文件类型校验逻辑

当前book字段仅校验文件名后缀,可结合mimetype提升校验严谨性:

const validateFileTypes = (req, file, cb) => {
  if (file.fieldname === "book") {
    const isPdf = file.originalname.endsWith(".pdf") && file.mimetype === "application/pdf";
    if (!isPdf) {
      return cb(new Error('"book"字段仅支持PDF文件'));
    }
  }

  if (file.fieldname === "coverImage" && !file.mimetype.startsWith("image/")) {
    return cb(new Error('"coverImage"字段仅支持图片文件'));
  }

  cb(null, true);
};

验证效果

修改完成后测试:

  • 上传合法文件:正常返回成功响应
  • 上传非法文件:服务器立即返回对应错误信息
  • 未选择文件提交:前端直接提示用户,不会发送无效请求

内容的提问来源于stack exchange,提问作者Official tashif

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:58:12