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日志。这说明状态变量至少更新过一次,但组件没有触发重渲染?
请问我哪里的实现存在问题?感谢各位的帮助!
修复方案
你的代码只需要调整几个细节即可正常实现进度跟踪:
- 补充async修饰符
你的handleChange函数内使用了await语法,但本身没有标记为async,属于基础语法错误,首先调整函数定义:
const handleChange = async (e: any) => {
- 调整分块上传参数
@aws-sdk/lib-storage的Upload类默认分块阈值为5MB,小于该大小的文件会走单块上传,仅会在上传完成时触发一次进度回调,也就是你看到的直接输出100%的情况。你可以手动调低分块大小,让小文件也能触发多次进度更新:
const upload = new Upload({ client: s3, params: target, partSize: 1024 * 1024, // 每块1MB,可根据实际需求调整 queueSize: 4 // 并发上传的分块数,默认值为4 });
- 可选优化:补充状态初始值
你可以给进度状态设置初始值0,避免初始状态下进度条不渲染的问题:
const [progr, setProgr] = useState<number>(0);
- 可选校验:检查S3 CORS配置
确保你的S3存储桶CORS配置的ExposeHeaders中包含ETag,分块上传完成后需要读取该字段做校验,缺失可能会导致上传完成后报错。
你原本的状态更新逻辑没有问题,setProgr本身会触发组件重渲染,调整以上内容后即可看到进度条随上传过程逐步更新。
内容的提问来源于stack exchange,提问作者Flo Ragossnig
相关产品推荐
相关产品推荐

