Expo ImagePicker选图上传Supabase存储文件为空问题求助
Expo ImagePicker上传Supabase存储出现空文件/0字节问题解决
我想用Expo的ImagePicker从相册选头像,以userid.jpeg命名上传到Supabase存储,之后拿URL展示图片,但上传的文件要么是0字节要么是空内容。尝试用Blob但搞不懂,相关代码如下:
从相册选择图片的代码:
const pickImage = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: false, aspect: [4, 3], quality: 0.7, }); if (!result.canceled) { const selectedAsset = result.assets[0]; setProfileImage(selectedAsset.uri); } };
上传至Supabase存储的代码:
try { console.log("Starting upload..."); const sanitizedId = sanitizeFilename(userId); const filename = `${sanitizedId}.jpeg`; const blob = await fetch(imageUri).then((res) => res.blob()); console.log("Uploading blob..."); const { error } = await supabase .storage .from('profile-pictures') .upload(filename, blob, { cacheControl: '3600', contentType: 'image/jpeg', upsert: false }); if (error) { console.error('Error uploading profile picture:', error); return null; } console.log("Getting public URL..."); const { data } = await supabase .storage .from('profile-pictures') .getPublicUrl(filename); console.log('Profile picture URL:', data); return data; } catch (error) { console.error('Error in uploadProfilePictureToSupabase:', error); return null; }; const sanitizeFilename = (filename) => { return filename.replace(/[^\w.-]/g, ''); };
问题原因与解决方法
问题核心
Expo返回的本地文件URI(file://开头)无法直接通过fetch正确读取内容,导致生成的Blob为空,最终上传0字节文件。
方案1:用Expo FileSystem转Base64再生成Blob
先安装expo-file-system,然后修改上传逻辑:
import * as FileSystem from 'expo-file-system'; // 上传函数中替换Blob生成部分 const fileInfo = await FileSystem.getInfoAsync(imageUri); if (!fileInfo.exists) { console.error('目标文件不存在'); return null; } // 读取文件为Base64 const base64Str = await FileSystem.readAsStringAsync(imageUri, { encoding: FileSystem.EncodingType.Base64 }); // 将Base64转为Blob const byteArray = Uint8Array.from(atob(base64Str), c => c.charCodeAt(0)); const blob = new Blob([byteArray], { type: 'image/jpeg' });
方案2:直接使用Expo返回的File对象(SDK 48+支持)
Expo SDK 48及以上版本中,ImagePicker返回的asset包含file属性,可直接用于上传:
// 修改选择图片函数,保存File对象 const pickImage = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: false, aspect: [4, 3], quality: 0.7, }); if (!result.canceled) { const selectedAsset = result.assets[0]; setProfileImage(selectedAsset.uri); // 新增状态保存File对象 setSelectedFile(selectedAsset.file); } }; // 上传时直接传入File对象 const { error } = await supabase .storage .from('profile-pictures') .upload(filename, selectedFile, { cacheControl: '3600', contentType: 'image/jpeg', upsert: false });
额外注意事项
- 确保
imageUri或selectedFile正确传递到上传函数,避免未定义 - 检查Supabase存储桶的权限配置,确保拥有上传权限
- 大文件使用Base64转换时注意内存占用,优先用File方案
内容的提问来源于stack exchange,提问作者elvis obondo
相关产品推荐
相关产品推荐

