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

React Redux+Redux-Observable中Axios上传S3进度状态不更新问题

解决React Redux + Redux-Observable中Axios上传S3的进度状态不更新问题

我之前也踩过类似的坑!明明上传成功了,但进度条纹丝不动,确实挺闹心的。结合你用的技术栈,咱们从几个关键环节排查解决:

1. 确保Axios的onUploadProgress回调正确触发并dispatch action

首先,Axios的进度回调需要直接在请求配置里定义,而且要注意S3 PUT请求的核心特性——必须在请求头里指定Content-Length,否则Axios无法计算上传进度。另外,要确保回调里的action能正确被Redux捕获。

示例代码:

// 构建S3上传请求
const uploadFileToS3 = (file, signedUrl) => {
  const config = {
    headers: {
      'Content-Length': file.size, // 关键:必须传入文件大小用于进度计算
      'Content-Type': file.type,
    },
    onUploadProgress: (progressEvent) => {
      const percentCompleted = Math.round(
        (progressEvent.loaded * 100) / progressEvent.total
      );
      // 触发更新进度的Redux action
      store.dispatch({
        type: 'UPLOAD_PROGRESS',
        payload: percentCompleted,
      });
    },
  };

  return axios.put(signedUrl, file, config);
};

2. 在Redux-Observable Epic中正确处理进度事件

如果你的上传逻辑是在Epic里管理的,要注意:onUploadProgress是请求过程中异步触发的,你需要把这些进度事件转化为Redux action,不能只处理请求的最终成功/失败结果。

可以通过创建Subject来监听进度回调,再和主请求流合并:

import { ofType } from 'redux-observable';
import { map, mergeMap, merge, from, catchError, of } from 'rxjs';
import { Subject } from 'rxjs';
import axios from 'axios';

const uploadEpic = (action$) =>
  action$.pipe(
    ofType('START_UPLOAD'),
    mergeMap((action) => {
      const { file, signedUrl } = action.payload;
      // 创建Subject接收进度事件
      const progressSubject = new Subject();

      const uploadRequest = axios.put(signedUrl, file, {
        headers: {
          'Content-Length': file.size,
          'Content-Type': file.type,
        },
        onUploadProgress: (event) => {
          const percent = Math.round((event.loaded * 100) / event.total);
          progressSubject.next({ type: 'UPLOAD_PROGRESS', payload: percent });
        },
      });

      // 合并进度流和请求结果流
      return merge(
        progressSubject,
        from(uploadRequest).pipe(
          map(() => ({ type: 'UPLOAD_SUCCESS' })),
          catchError((err) => of({ type: 'UPLOAD_FAILURE', payload: err }))
        )
      );
    })
  );

3. 检查Upload Reducer是否正确处理进度action

最后,别漏了在reducer里添加对应分支更新progress状态:

const initialState = {
  progress: 0,
  isUploading: false,
  error: null,
};

const uploadReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'START_UPLOAD':
      return { ...state, isUploading: true, progress: 0 };
    case 'UPLOAD_PROGRESS':
      return { ...state, progress: action.payload }; // 这里必须更新进度值!
    case 'UPLOAD_SUCCESS':
      return { ...state, isUploading: false, progress: 100 };
    case 'UPLOAD_FAILURE':
      return { ...state, isUploading: false, error: action.payload };
    default:
      return state;
  }
};

额外注意点

  • 如果你的上传用了S3分块上传(Multipart Upload),Axios的onUploadProgress只会返回单块的进度,需要自己累加计算总进度;单文件PUT的话,上面的方法完全适用。
  • 测试时尽量用大文件,小文件上传太快可能看不到进度变化,容易误以为回调没触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:18:11