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

React+Node+Axios响应异常:无法捕获文件上传错误

问题描述

我用React.js前端和Node.js后端开发时,遇到响应消息无法正常返回展示的问题。此前该功能正常,但修改文件上传中间件与Route.post逻辑以捕获已上传文件的情况后,现在无法捕获任何错误。相关代码如下:


React 前端代码

import React, { useState, useEffect } from 'react';
import './NewsAndFlyerUploadFlyers.css';
//Components
import Header from '../../Components/Header/Header';
import Footer from '../../Components/Footer/Footer';
//Repositories
import Axios from 'axios';
import { useNavigate } from 'react-router-dom';
import moment from 'react-moment';

const NewsAndFlyerUploadFlyers = () => {
    const [flyerName, setFullName] = useState(null);
    const [flyerEventDate, setFlyerEventDate] = useState(null);
    const [flyerDescription, setFlyerDescription] = useState(null);
    const [selectedFile, setSelectedFile] = useState(null);
    const [statusMessage, setStatusMessage] = useState(null);
    const [isLoading, setIsLoading] = useState(false);
    const Navigate = useNavigate();

    const submitForm = () => {
        setIsLoading(true);
        const url = 'http://localhost:3001/Flyer/Flyer_Upload';
        
        const data = new FormData();
        data.append('flyerName', flyerName);
        data.append('flyerEventDate', flyerEventDate);
        data.append('flyerDescription', flyerDescription);
        for (var x = 0; x < selectedFile.length; x++){
            data.append('files', selectedFile[x]);
        }
        
        Axios.post(url, data)
        .then((response) => {
            if (response.data.message != null){
                setStatusMessage(response.data.message);
            }
            else {
                Navigate('/NewsAndFlyers');
            }
        });
        setIsLoading(false);
    };

    return (
        <>
            <Header/>
            <div className='newsAndFlyersUploadFlyersBody'>
                <h1>Upload A Flyers</h1>
                <div className='flyerInfoFormBody'>
                <p className='flyerName'>*Event Name: <input name='flyerName' placeholder='Event Name' required autoComplete="off" onChange={(e) => setFullName(e.target.value)} /></p>
                <p className='flyerEventDate'>*Event Date: <input name='flyerEventDate' type='date' placeholder='Event Date' required autoComplete="off" onChange={(e) => setFlyerEventDate(e.target.value)} /></p>
                <p className='flyerDescription'>*Flyer Description: <textarea name='flyerDescription' placeholder='Flyer Description' required autoComplete="off" onChange={(e) => setFlyerDescription(e.target.value)} /> </p>
                <p>*Upload the flyer.</p>
                <input className='uploadFiles' type='file' name='file' required onChange={(e) => setSelectedFile(e.target.files)} /></div>
                {isLoading && <button className='uploadButton' disabled>Loading</button>}
                {!isLoading && <button className='uploadButton' onClick={submitForm}>Upload Flyer</button>}
                <h2>{statusMessage}</h2>
            </div>
            <Footer/>
        </>
    );
}

export default NewsAndFlyerUploadFlyers;

Node.js 文件上传中间件

const flyerDestination = './routes/Flyers'
const flyerStorage = multer.diskStorage({
  destination: function (req, file, cb){ 
    return cb(null, flyerDestination)
  },
  filename: function (req, file, cb){
    if (fs.existsSync(path.join(flyerDestination,file.originalname))) {
      return cb(new Error("Flyer already exists"));
    } else {
      return cb(null, file.originalname);
    }
  }
});
const flyerUpload = multer({ storage: flyerStorage }).array('files');

Node.js 路由代码

router.post('/Flyer_Upload', (req, res) => {
  flyerUpload(req, res, function (err) {
    const flyerName = req.body.flyerName;
    const flyerEventDate = req.body.flyerEventDate;
    const flyerDescription = req.body.flyerDescription;
    const flyerID = Math.floor(Math.random()*90000) + 10000;
    const flyerDirectory = 'http://localhost:3001/Flyers/';
    var uploadFlyer = true;
    var multerMessage = null;
    
    if (err instanceof multer.MulterError) {
      uploadFlyer = false;
      multerMessage = 'An Error Occurred During Upload!';
    } else if (res.status(409)) {
      uploadFlyer = false;
      multerMessage = 'Flyer already exists';
    } else if (res.status(500)){
      uploadFlyer = false;
      multerMessage = 'A Bad Request Was Recieved!';
    } else if (err){
      uploadFlyer = false;
      multerMessage = 'An Unknown Error Occurred!';
    }

    if (multerMessage == null){
      for (const file of req.files) {
        directory = path.dirname(file.path);
        const flyerUploadedPath = flyerDirectory + file.filename
        
        //Delete Once Successful
        console.log('flyerName: ' + flyerName);
        console.log('flyerEventDate: ' + flyerEventDate);
        console.log('flyerDescription: ' + flyerDescription);
        console.log('flyerID: ' + flyerID);      
        console.log('File path: ' + flyerUploadedPath);     

        db.query('INSERT INTO flyerinfo (flyerID, flyerName, flyerEventDate, flyerDescription, flyerURL) VALUES (?,?,?,?,?)', [flyerID, flyerName, flyerEventDate, flyerDescription, flyerUploadedPath], (err, res) => {
            if (err){
              return res.json({message: 'An Error Occurred!' });
            }
          });
        return res.status(200).send(req.files);
      }
    } else {
      console.log (multerMessage)
      return res.json({message: multerMessage });
    }
  });
});
module.exports = router;

问题分析与修复方案

核心问题点

  1. 前端未处理请求错误:Axios仅监听成功回调,未捕获网络错误或后端错误响应;setIsLoading(false)直接写在请求外,会导致请求未完成就关闭加载状态。
  2. 后端错误判断逻辑错误:res.status(409)是设置响应状态码的方法,不是错误判断条件;文件名重复的错误会被归类为"未知错误",无法返回对应提示。
  3. 变量作用域冲突:数据库查询回调中使用res参数,覆盖了外层的响应对象,导致数据库错误时无法正常返回响应。
  4. 文件处理逻辑缺陷:循环处理文件时,第一个文件就执行return res,导致多文件仅处理第一个;且数据库插入是异步操作,提前return会导致插入未完成就返回响应。
  5. 状态变量命名混乱:setFullName对应flyerName状态,命名不一致易引发bug。

修复后的前端代码(关键调整)

const submitForm = () => {
    setIsLoading(true);
    const url = 'http://localhost:3001/Flyer/Flyer_Upload';
    
    const data = new FormData();
    data.append('flyerName', flyerName);
    data.append('flyerEventDate', flyerEventDate);
    data.append('flyerDescription', flyerDescription);
    for (var x = 0; x < selectedFile.length; x++){
        data.append('files', selectedFile[x]);
    }
    
    Axios.post(url, data)
    .then((response) => {
        if (response.data.message != null){
            setStatusMessage(response.data.message);
        }
        else {
            Navigate('/NewsAndFlyers');
        }
    })
    .catch((error) => {
        // 捕获所有请求错误并展示
        setStatusMessage(error.response?.data?.message || '上传失败,请重试');
    })
    .finally(() => {
        // 请求完成后统一关闭加载状态
        setIsLoading(false);
    });
};

// 同时修正状态变量命名
const [flyerName, setFlyerName] = useState(null);
// 对应input的onChange改为setFlyerName
<input name='flyerName' placeholder='Event Name' required autoComplete="off" onChange={(e) => setFlyerName(e.target.value)} />

修复后的后端路由代码

router.post('/Flyer_Upload', (req, res) => {
  flyerUpload(req, res, function (err) {
    const flyerName = req.body.flyerName;
    const flyerEventDate = req.body.flyerEventDate;
    const flyerDescription = req.body.flyerDescription;
    const flyerID = Math.floor(Math.random()*90000) + 10000;
    const flyerDirectory = 'http://localhost:3001/Flyers/';
    var multerMessage = null;
    
    // 修正错误判断逻辑
    if (err instanceof multer.MulterError) {
      multerMessage = '上传过程中发生错误!';
    } else if (err && err.message === "Flyer already exists") {
      multerMessage = '该文件已存在!';
      res.status(409);
    } else if (err){
      multerMessage = '发生未知错误!';
      res.status(500);
    }

    if (multerMessage) {
      console.log(multerMessage);
      return res.json({message: multerMessage });
    }

    // 用Promise处理异步数据库操作,确保所有文件插入完成后再返回
    const insertPromises = req.files.map(file => {
      const flyerUploadedPath = flyerDirectory + file.filename;
      return new Promise((resolve, reject) => {
        db.query(
          'INSERT INTO flyerinfo (flyerID, flyerName, flyerEventDate, flyerDescription, flyerURL) VALUES (?,?,?,?,?)', 
          [flyerID, flyerName, flyerEventDate, flyerDescription, flyerUploadedPath], 
          (err, result) => {
            if (err){
              reject('插入数据库失败!');
            } else {
              resolve(result);
            }
          }
        );
      });
    });

    Promise.all(insertPromises)
      .then(() => {
        res.status(200).json({message: null});
      })
      .catch(dbErr => {
        res.status(500).json({message: dbErr});
      });
  });
});
module.exports = router;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 09:05:01