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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:15:17