使用Expo+Amplify+S3上传图片仅生成空文件,报NoSuchUpload错误
问题分析与解决方案
核心问题
- 异步操作未正确等待:
Storage.put是异步函数,代码中未添加await,导致上传流程未完成就结束,触发未处理的Promise拒绝,同时上传中断生成空文件。 - Expo本地URI转Blob方式错误:React Native环境下,
fetch无法正确解析file://开头的本地图片URI,导致生成的Blob内容为空或无效,S3仅接收了空文件片段。
解决方案
方案1:直接使用本地URI上传(推荐,无需转Blob)
Amplify Storage在React Native中支持直接传入本地文件URI,无需手动转换Blob。修改上传函数如下:
const uploadImageToStorage = async () => { try { const fileName = `${uuidv4()}.jpg`; // 直接传入图片URI,指定正确的内容类型 await Storage.put(fileName, image, { contentType: 'image/jpeg', // 根据实际图片类型调整,如image/png level: 'public' // 按需设置存储级别:public/private/protected }); console.log('Image uploaded successfully!'); } catch (error) { console.log('Error uploading file:', error); } };
方案2:使用Expo FileSystem正确转换Blob
如果必须使用Blob上传,借助expo-file-system读取本地文件内容:
- 先安装依赖:
npx expo install expo-file-system
- 修改上传函数:
import * as FileSystem from 'expo-file-system'; // ... const uploadImageToStorage = async () => { try { const fileName = `${uuidv4()}.jpg`; // 读取本地图片为Base64格式 const base64Content = await FileSystem.readAsStringAsync(image, { encoding: FileSystem.EncodingType.Base64, }); // 将Base64转为ArrayBuffer再生成Blob const arrayBuffer = Uint8Array.from(atob(base64Content), c => c.charCodeAt(0)).buffer; const blob = new Blob([arrayBuffer], { type: 'image/jpeg' }); await Storage.put(fileName, blob, { contentType: 'image/jpeg', }); console.log('Image uploaded successfully!'); } catch (error) { console.log('Error uploading file:', error); } };
额外检查项
- 确认
aws-exports.js中aws_user_files_s3_bucket和aws_user_files_s3_bucket_region与S3桶信息完全匹配。 - 检查S3桶的IAM权限策略,确保Amplify关联的IAM角色拥有
s3:PutObject权限。 - 若允许选择多种图片类型(如PNG),建议根据
result.assets[0].mimeType动态设置contentType和文件后缀,避免格式不匹配。
内容的提问来源于stack exchange,提问作者ANDREI MIRONOV
相关产品推荐
相关产品推荐

