React Native Expo+Clerk认证上传Supabase存储失败及RLS配置疑问
问题解决:Expo图片上传Supabase失败 + Clerk认证下的存储桶RLS配置
一、解决「No content provided」上传失败问题
1. 修复本地文件读取逻辑(核心问题)
React Native的fetch对file://协议的本地文件支持不稳定,易导致获取的Blob为空。改用expo-file-system读取文件内容并转换为Blob:
首先安装依赖:
npx expo install expo-file-system
导入模块并修改uploadMedia函数:
import * as FileSystem from 'expo-file-system'; const uploadMedia = async ( uri: string, mediaType: 'images' | 'videos', supabaseClient: SupabaseClient, userId: string // 新增用户ID,用于RLS验证 ): Promise<string | null> => { try { const extension = uri.split('.').pop() || 'jpg'; const filename = `${uuidv4()}.${extension}`; // 路径加入用户ID,方便后续RLS规则校验 const path = `${mediaType}/${userId}/${filename}`; // 验证文件存在性 const fileInfo = await FileSystem.getInfoAsync(uri); if (!fileInfo.exists) throw new Error('文件不存在'); // 读取文件为base64并转换为Blob const base64 = await FileSystem.readAsStringAsync(uri, { encoding: 'base64' }); const mimeType = mediaType === 'images' ? `image/${extension === 'png' ? 'png' : 'jpeg'}` : 'video/mp4'; const blob = new Blob([Buffer.from(base64, 'base64')], { type: mimeType }); if (blob.size === 0) throw new Error('生成的Blob为空'); console.log('上传Blob信息:', { size: blob.size, type: blob.type }); // 上传时附加用户元数据(可选,配合RLS) const { error } = await supabaseClient.storage .from('food-listings-media') .upload(path, blob, { metadata: { user_id: userId } }); if (error) throw error; const { data: { publicUrl } } = supabaseClient.storage .from('food-listings-media') .getPublicUrl(path); if (!publicUrl) throw new Error('获取公网URL失败'); return publicUrl; } catch (error) { console.error('上传媒体错误:', error); return null; } };
2. 修正URI处理逻辑
expo-image-manipulator.manipulateAsync返回的URI已是有效的file://格式,无需手动重复添加。调用uploadMedia时传入用户ID:
const imageUrl = await uploadMedia(compressedImage.uri, 'images', supabaseClient, user.id);
额外提示
确保handleSubmit中使用的变量已从listing正确解构:
const { images, videos, title, description, selectedCuisine, maxGuests, pricePerMeal, location, rules, availability } = listing;
二、Clerk认证下的Supabase存储桶RLS配置
1. 前置关联配置
在Supabase控制台完成以下操作:
- 进入Settings > Auth > JWT,在External OAuth Providers中添加Clerk的JWKS URL(可在Clerk Dashboard的API Keys页面获取),确保Supabase能验证Clerk签发的JWT。
- 启用存储桶RLS:进入Storage > Buckets > food-listings-media > Edit,勾选Enable Row Level Security。
2. 创建RLS规则
在Supabase SQL编辑器中执行以下规则:
(1)允许认证用户上传自有媒体
CREATE POLICY "认证用户可上传自有媒体" ON storage.objects FOR INSERT TO authenticated WITH CHECK ( bucket_id = 'food-listings-media' AND -- 验证JWT用户ID与路径中的用户ID一致 auth.jwt() ->> 'sub' = split(path, '/')[1] );
(2)允许认证用户查看自有媒体
CREATE POLICY "认证用户可查看自有媒体" ON storage.objects FOR SELECT TO authenticated USING ( bucket_id = 'food-listings-media' AND auth.jwt() ->> 'sub' = split(path, '/')[1] );
(3)允许匿名用户查看公开媒体(可选)
CREATE POLICY "匿名用户可查看公开媒体" ON storage.objects FOR SELECT TO anon USING ( bucket_id = 'food-listings-media' );
(4)允许认证用户删除自有媒体(可选)
CREATE POLICY "认证用户可删除自有媒体" ON storage.objects FOR DELETE TO authenticated USING ( bucket_id = 'food-listings-media' AND auth.jwt() ->> 'sub' = split(path, '/')[1] );
内容的提问来源于stack exchange,提问作者asim san
相关产品推荐
相关产品推荐

