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

上传图片文件时请求无限处于pending状态问题排查

问题现象

上传包含图片、视频文件的文章到数据库时,全流程无报错抛出,但请求始终停留在pending状态,无响应返回。


相关代码片段

前端表单提交逻辑

const [formdata, setFormdata] = useState(
  {
    ressort:"",
    theme:"",
    title:"",
    content:"",
  }
)
const {ressort,theme,title,content} = formdata;
const [fileData, setFileData] = useState({
  img:""
})
const {img} = fileData;
const fileInput = useRef(img);
const fileChange = (e)=>{
  console.log(fileInput.current.files);
  setFileData(fileInput.current.files[0])
}
console.log(fileData); //works
const handleChange = (e)=>{
  setFormdata((prevState)=>({
    ...prevState,
    [e.target.name]: e.target.value
  }))
}
const onSubmit = (e)=>{
  e.preventDefault();
  const data = new FormData();
  data.append("img", fileData);
  console.log(data);
  const mainnewsData ={
    data,
    ressort,
    theme,
    title,
    content
  }
  console.log(mainnewsData);
  dispatch(createMainNews(mainnewsData));
}

Redux异步Thunk逻辑

export const createMainNews = createAsyncThunk("mainNews/create", async (mainnewsData, thunkAPI)=>{
  try{
      const token = thunkAPI.getState().auth.user.token;
      return await mainnewsService.createMainNews(mainnewsData, token);
  } catch(error){
      const message = (error.response && 
          error.response.data && 
          error.response.data.message)
          || error.message
          || error.toString()
          return thunkAPI.rejectWithValue(message);
  }
})

服务层Axios请求代码

const API_URL = "http://localhost:5000/api/mainNews/";
const createMainNews = async (mainnewsData, token)=>{
  const config = {
      headers: {
          "Content-Type": "multipart/form-data",
          "token": `Bearer ${token}`
        },
  }
  const response = await axios.post(API_URL, mainnewsData, config);
  return response.data;
}

后端接口实现(基于Express+Multer)

router.post("/", verifyTokenAndAuthorization,upload.single("img"), async (req,res)=>{
  const newMainNews = new MainNews({
      img: req.file.originalname,
      ressort: req.body.ressort,
      theme: req.body.theme,
      title: req.body.title,
      content:req.body.content,
  });
  try{
      const savedMainNews = await newMainNews.save();
      res.status(200).json(savedMainNews);
  } catch(error){
      res.status(403)
      throw new Error("Aktion fehlgeschlagen");
  }
});

根因分析与修复方案

请求卡pending是前后端传参、解析、响应逻辑的多个问题共同导致的,逐个修复即可:

  1. FormData传参结构错误
    把FormData实例嵌套在普通对象mainnewsData里,和其他文本字段平级传递时,Axios无法正确识别并序列化FormData内容,后端Multer拿不到文件、普通字段也解析失败。
    修复方式:所有文本字段和文件都要追加到同一个FormData实例中,直接传递FormData实例,不要套额外的普通对象。
    修正后的提交逻辑:

    const onSubmit = (e)=>{
      e.preventDefault();
      const data = new FormData();
      // 追加文件
      data.append("img", fileData);
      // 所有文本字段统一追加到FormData
      data.append("ressort", ressort);
      data.append("theme", theme);
      data.append("title", title);
      data.append("content", content);
      // 直接传FormData实例
      dispatch(createMainNews(data));
    }
    

    顺带修正fileData初始值的冗余问题,初始值直接设为null即可,不需要嵌套对象:

    const [fileData, setFileData] = useState(null)
    
  2. 手动设置multipart/form-data请求头导致解析失败
    multipart/form-data请求头必须携带浏览器自动生成的boundary分隔符,手动写死该请求头会导致分隔符丢失,后端无法正确切割请求体内容,会一直等待完整数据传入。
    修复方式:删除手动配置的Content-Type头,Axios在识别到传递的是FormData实例时,会自动设置正确的请求头和boundary。
    修正后的请求配置:

    const createMainNews = async (mainnewsData, token)=>{
      const config = {
          headers: {
              // 删除手动写的Content-Type配置
              "Authorization": `Bearer ${token}` // 建议使用标准Authorization头传递JWT,若后端自定义读取token字段可保留原配置
            },
      }
      const response = await axios.post(API_URL, mainnewsData, config);
      return response.data;
    }
    
  3. 后端错误处理不返回响应,导致请求挂起
    现有后端代码把req.file.originalname等字段读取逻辑放在了try块外面,一旦Multer解析失败、req.file为undefined,会直接抛出同步错误;同时catch块内只设置了HTTP状态码,没有返回任何响应内容,前端会一直等待后端返回直到超时。
    修复方式:把所有业务逻辑移入try块,所有异常分支都要明确返回响应。
    修正后的后端路由:

    router.post("/", verifyTokenAndAuthorization,upload.single("img"), async (req,res)=>{
      try{
          // 先校验文件是否上传成功
          if(!req.file) {
            return res.status(400).json({message: "文件上传失败"});
          }
          const newMainNews = new MainNews({
              img: req.file.originalname,
              ressort: req.body.ressort,
              theme: req.body.theme,
              title: req.body.title,
              content:req.body.content,
          });
          const savedMainNews = await newMainNews.save();
          res.status(200).json(savedMainNews);
      } catch(error){
          // 错误场景必须返回响应,不能只设置状态码
          res.status(500).json({message: "操作失败"})
      }
    });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 12:18:23