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

React使用AWS SDK v3上传文件到S3时进度监听异常问题求助

我最近才开始接触AWS SDK,如果我的实现思路完全不合理还请谅解。

我需要将简单的媒体文件上传到我的S3存储桶,之前参考了官方教程,目前已经可以无异常完成文件上传。为了提升可用性,我希望额外添加进度条功能,因此调研了对应的实现方案。我很快发现当前的AWS SDK v3已经不再支持httpUploadProgress,需要改用@aws-sdk/lib-storage实现。使用该库后我依然可以正常上传文件到S3,但进度跟踪功能始终无法生效!我猜测该问题和我没有完全掌握React组件中async异步逻辑的处理方式有关。

以下是我精简后的组件示例(此处使用了Chakra UI组件库):

const TestAWS: React.FC = () => {
  const inputRef = useRef<HTMLInputElement | null>(null);
  const [progr, setProgr] = useState<number>();

  const region = "eu-west-1";
  const bucketname = "upload-test";

  const handleClick = async () => {
    inputRef.current?.click();
  };

  const handleChange = (e: any) => {

    console.log('Start file upload');

    const file = e.target.files[0];
    const target = {
      Bucket: bucketname,
      Key: `jobs/${file.name}`,
      Body: file,
    };

    const s3 = new S3Client({
      region: region,
      credentials: fromCognitoIdentityPool({
        client: new CognitoIdentityClient({ region: region }),
        identityPoolId: "---MY ID---",
      }),
    });

    const upload = new Upload({
      client: s3,
      params: target,
    });

    const t = upload.on("httpUploadProgress", progress => {
      console.log("Progress", progress);

      if (progress.loaded && progress.total) {
        console.log("loaded/total", progress.loaded, progress.total);
        setProgr(Math.round((progress.loaded / progress.total) * 100)); // 我本以为这行代码就足够更新我的组件
      }
    });
    await upload.done().then(r => console.log(r));
  };

console.log('Progress', progr);

return (
    <InputGroup onClick={handleClick}>
      <input ref={inputRef} type={"file"} multiple={false} hidden accept='video/*' onChange={e => handleChange(e)} />
      <Flex layerStyle='uploadField'>
        <Center w='100%'>
          <VStack>
            <PlusIcon />
            <Text>Choose Video File</Text>
          </VStack>
        </Center>
      </Flex>
      {progr && <Progress value={progr} />}
    </InputGroup>
  );
};

export default TestAWS;

目前的现象是我可以看到事件触发(打印“Start file upload”日志),之后等待一段时间就会看到Promise返回结果,同时控制台打印Progress, 100日志。这说明状态变量至少更新过一次,但组件没有触发重渲染?

请问我哪里的实现存在问题?感谢各位的帮助!


修复方案

你的代码只需要调整几个细节即可正常实现进度跟踪:

  1. 补充async修饰符
    你的handleChange函数内使用了await语法,但本身没有标记为async,属于基础语法错误,首先调整函数定义:
const handleChange = async (e: any) => {
  1. 调整分块上传参数
    @aws-sdk/lib-storage的Upload类默认分块阈值为5MB,小于该大小的文件会走单块上传,仅会在上传完成时触发一次进度回调,也就是你看到的直接输出100%的情况。你可以手动调低分块大小,让小文件也能触发多次进度更新:
const upload = new Upload({
  client: s3,
  params: target,
  partSize: 1024 * 1024, // 每块1MB,可根据实际需求调整
  queueSize: 4 // 并发上传的分块数,默认值为4
});
  1. 可选优化:补充状态初始值
    你可以给进度状态设置初始值0,避免初始状态下进度条不渲染的问题:
const [progr, setProgr] = useState<number>(0);
  1. 可选校验:检查S3 CORS配置
    确保你的S3存储桶CORS配置的ExposeHeaders中包含ETag,分块上传完成后需要读取该字段做校验,缺失可能会导致上传完成后报错。

你原本的状态更新逻辑没有问题,setProgr本身会触发组件重渲染,调整以上内容后即可看到进度条随上传过程逐步更新。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 01:24:05