从 Supabase Storage 迁移
PG 模式云存储与 Supabase Storage 在 storage schema、Bucket / Object 元数据模型和 RLS 思路上高度相似。如果你的应用主要使用 Supabase 的 File Buckets,可以按本文迁移到 CloudBase。
迁移前确认
迁移前请先确认现有 Supabase Storage 的使用范围:
| 检查项 | 说明 |
|---|---|
| Bucket 类型 | 迁移对象应是通用文件 Bucket,例如图片、视频、文档、压缩包 |
| 访问模型 | Public / Private Bucket、Signed URL、Authenticated download |
| RLS Policy | storage.objects 上的 SELECT / INSERT / UPDATE / DELETE 策略 |
| 路径规则 | 是否使用 <uid>/<filename>、<team_id>/<filename> 等路径约定 |
| 上传限制 | 文件大小限制、MIME 类型限制 |
| SDK API | 是否使用 upload、download、list、remove、createSignedUrl 等能力 |
建议先选一个低风险 Bucket 做试迁移,例如 avatars 或测试附件 Bucket。
可复用的内容
以下内容通常可以复用或少量调整后复用:
| Supabase Storage 内容 | CloudBase 对应内容 |
|---|---|
storage.buckets | storage.buckets |
storage.objects | storage.objects |
bucket_id | bucket_id |
name 对象路径 | name 对象路径 |
owner_id | owner_id |
metadata / user_metadata | metadata / user_metadata |
storage.foldername(name) | storage.foldername(name) |
storage.filename(name) | storage.filename(name) |
| 大部分 RLS Policy 思路 | 可迁移为 CloudBase RLS Policy |
例如,按用户目录隔离的策略通常只需确认 auth.uid()、角色名和 Bucket ID 是否一致。
CREATE POLICY user_files_select ON storage.objects
FOR SELECT TO authenticated
USING (
bucket_id = 'user-files'
AND (storage.foldername(name))[1] = auth.uid()
);
需要调整的内容
public 语义需要复核
在 CloudBase PG 模式中,storage.buckets.public 是元数据标记,不会自动绕过 RLS。是否公开可读,仍由 storage.objects 上的 SELECT Policy 决定。
如果 Supabase 中某个 Public Bucket 依赖「知道 URL 即可访问」的语义,迁移后需要显式补充公开读策略:
CREATE POLICY objects_public_read ON storage.objects
FOR SELECT TO anon, authenticated
USING (
EXISTS (
SELECT 1 FROM storage.buckets b
WHERE b.id = storage.objects.bucket_id
AND b.public
)
);
SDK 初始化和项目配置不同
Supabase:
import { createClient } from '@supabase/supabase-js';
const supabase = createClient('<project-url>', '<anon-key>');
const bucket = supabase.storage.from('avatars');
CloudBase:
import cloudbase from '@cloudbase/js-sdk';
const app = cloudbase.init({ env: '<env-id>' });
const bucket = app.storage.from('avatars');
返回字段和 URL 字段需要复核
不同 SDK 的返回字段不完全一致。迁移时请重点检查:
- 上传返回对象 ID、路径、完整路径;
- 签名下载链接字段,例如
signedUrl/fullSignedURL; - 公开 URL 字段;
- 错误对象结构;
- 列表分页字段,例如
hasNext、nextCursor。
上传协议和高级能力需要重新设计
如果 Supabase 项目使用了 TUS 可恢复上传、S3 兼容协议、图片实时转换、特定 CDN Header 或其他高级能力,请先确认 CloudBase 当前对应能力和推荐接入方式,再迁移相关业务逻辑。
对于普通 File Bucket 场景,优先迁移以下稳定能力:
- Bucket 创建与配置;
- 文件上传 / 下载;
- 文件列表;
- 复制 / 移动 / 删除;
- 签名下载 / 签名上传;
- RLS 权限策略。
推荐迁移步骤
1. 梳理 Bucket 清单
为每个 Bucket 记录:
Bucket: avatars
用途:用户头像
Public:false
大小限制:5 MB
MIME:image/png、image/jpeg、image/webp
路径:<uid>/avatar.png
权限:本人写,按业务读取
2. 在 CloudBase 创建 Bucket
INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
VALUES (
'avatars',
'avatars',
false,
5 * 1024 * 1024,
ARRAY['image/png', 'image/jpeg', 'image/webp']
);
3. 迁移文件实体
根据源 Bucket 和目标 Bucket 的规模选择迁移方式:
- 小规模:通过 SDK 下载后重新上传;
- 中等规模:编写服务端脚本批量迁移;
- 大规模:结合对象存储后端工具迁移文件实体,再补齐元数据。
迁移脚本 必须使用环境变量保存密钥,不要把 Supabase service key、CloudBase API Key 或腾讯云密钥写入代码仓库。
4. 迁移元数据和业务引用
如果业务表中保存了 Supabase 文件 URL,建议迁移为稳定的 Bucket 内对象路径,例如:
avatars/user-123/avatar.png
业务表保存对象路径,展示时再生成公开 URL 或签名 URL。这样后续更换域名、访问方式或 CDN 配置时,不需要批量修改业务数据。
5. 迁移 RLS Policy
按 Bucket 逐条迁移 SELECT、INSERT、UPDATE、DELETE Policy。每条 Policy 迁移后都应验证:
- owner 可以访问自己的文件;
- 非 owner 不能访问;
- 匿名用户权限符合预期;
service_role仅在服务端使用。
6. 替换 SDK 调用
常见替换关系:
| Supabase | CloudBase |
|---|---|
supabase.storage.from(bucket) | app.storage.from(bucket) |
bucket.upload(path, file, options) | bucket.upload(path, file, options) |
bucket.download(path) | bucket.download(path) |
bucket.list(prefix, options) | bucket.list(prefix, options) |
bucket.remove(paths) | bucket.remove(paths) |
bucket.createSignedUrl(path, expiresIn) | bucket.createSignedUrl(path, expiresIn) |
bucket.getPublicUrl(path) | bucket.getPublicUrl(path) |
方法名相近不代表返回结构完全一致,迁移时请以 JS SDK Storage API 为准。
7. 做权限回归测试
至少覆盖以下用例:
| 用例 | 预期 |
|---|---|
| owner 上传自己的文件 | 成功 |
| owner 下载自己的文件 | 成功 |
| 非 owner 下载他人私有文件 | 失败 |
| 匿名访问公开文件 | 按公开读策略决定 |
| 匿名访问私有文件 | 失败 |
| owner 覆盖自己的文件 | 按 UPDATE Policy 决定 |
| 非管理员删除团队文件 | 失败 |
| 管理员删除团队文件 | 成功 |
AI 友好迁移清 单
如果你希望让 AI 辅助迁移,建议按 Bucket 提供结构化清单,而不是直接丢一整份 SQL:
源:Supabase Storage
目标:CloudBase PG 云存储
Bucket: avatars
用途:用户头像
路径:<uid>/avatar.png
Public:否
读取:所有登录用户可读
上传:仅本人可上传到自己的 <uid>/ 目录
覆盖:仅本人可覆盖自己的头像
删除:仅本人可删除自己的头像
限制:5 MB;image/png、image/jpeg、image/webp
需要迁移:Bucket 创建 SQL、RLS Policy、JS SDK 上传和签名 URL 代码
这样 AI 可以分别生成 Bucket SQL、RLS、SDK 替换代码和测试用例,减少遗漏。