# 文件存储

## 创建存储桶

通过 SQL 迁移创建存储桶：

```sql
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true);
```

## 关键上传方法


**必须使用 ArrayBuffer**（通过 `base64-arraybuffer`）进行所有文件上传。使用 `Blob`、`File` 或 `FormData` 会导致 `400 InvalidRequest "No content provided"` 错误。
**注意**：必须通过友好的 Toast 交互提醒用户数据操作结果，特别是操作失败的情况。
**重要约束：必须在前端上传文件。禁止在云函数（Edge Functions）中上传文件**，因为云函数上传的文件无法获取公网访问 URL，会导致前端无法正常访问和显示文件。所有文件上传操作必须在前端（浏览器环境）中进行。

> 记得在 `package.json` 中添加 `base64-arraybuffer` 依赖。

```typescript
import { decode } from 'base64-arraybuffer';

// ✅ 从 base64 字符串上传（必须检查 error）
const { data, error } = await supabase.storage
  .from('avatars')
  .upload('public/avatar1.png', decode('base64FileData'), {
    contentType: 'image/png'
  });

if (error) throw new Error(`上传失败: ${error.message}`);

// 从文件输入上传（先转换为 ArrayBuffer）
const reader = new FileReader();
reader.onload = async (e) => {
  const base64 = (e.target?.result as string).split(',')[1];
  const { data, error } = await supabase.storage
    .from('bucket-name')
    .upload(`path/${file.name}`, decode(base64), {
      contentType: file.type,
    });

  if (error) {
    console.error('上传失败:', error.message);
    return;
  }
};
reader.readAsDataURL(file);
```

```typescript
// ❌ 错误做法 — 会导致 400 错误
const formData = new FormData();
formData.append('file', file);
await supabase.storage.from('bucket').upload('path', formData); // ❌
await supabase.storage.from('bucket').upload('path', blob);     // ❌
await supabase.storage.from('bucket').upload('path', file);     // ❌
```




## 存储 RLS 策略

```sql
-- 创建存储桶的 RLS 策略
CREATE POLICY anon_select_avatars ON storage.objects
FOR SELECT USING (bucket_id = 'avatars');

CREATE POLICY users_insert_avatars ON storage.objects
FOR INSERT WITH CHECK (
  bucket_id = 'avatars' AND
  auth.role() = 'authenticated'
);
```

## Edge Functions 存储限制


**重要**：存储操作应在前端执行，而非 Edge Functions。Edge Functions 使用私有网络 URL，无法提供文件的公开访问。



## 存储模式限制

不要在 `storage` 模式中执行以下操作：
- 创建自定义表或函数
- 删除现有表或函数
- 在现有存储表上创建索引
- 对 `storage.migrations` 执行破坏性操作

管理文件访问请在 `public` 模式中创建辅助函数。