Bucket 管理
Bucket 是 PG 模式云存储中组织文件的基础容器。每个 Bucket 对应 storage.buckets 表中的一行,文件对象的元数据则写入 storage.objects,并通过 bucket_id 关联到所属 Bucket。
如果你熟悉 Supabase Storage,可以把这里理解为面向通用文件的 File Bucket:用于存储图片、视频、文档、压缩包、用户上传内容和静态资源。
什么时候拆分 Bucket
建议按访问模型、上传限制和业务生命周期拆分 Bucket,而不是简单按目录拆分。
| 场景 | 推荐 Bucket | 典型路径 | 推荐权限模型 |
|---|---|---|---|
| 用户头像 | avatars | <uid>/avatar.png | 本人写,按业务决定是否公开读 |
| 公开静态资源 | public-assets | logos/cloudbase.png | 公开读,服务端写 |
| 用户私有文件 | private-files | <uid>/<filename> | 仅本人读写 |
| 团队协作文件 | team-files | <team_id>/<filename> | JOIN 业务表判断团队成员 |
| 文章 / 订单附件 | article-assets | articles/<article_id>/<filename> | 跟随业务对象权限 |
如果两类文件的访问权限、大小限制、MIME 类型限制或清理策略不同,通常应拆成不同 Bucket。
创建 Bucket
你可以通过 JS SDK、HTTP API、SQL 或管理端 SDK 创建 Bucket。下面以 JS SDK 和 SQL 为例。
JS SDK
import cloudbase from '@cloudbase/js-sdk';
const app = cloudbase.init({ env: '<env-id>' });
const { data, error } = await app.storage.createBucket('avatars', {
public: false,
fileSizeLimit: 5 * 1024 * 1024,
allowedMimeTypes: ['image/png', 'image/jpeg', 'image/webp'],
});
if (error) {
throw error;
}
console.log(data.id);
SQL
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']
);
更多方式见 快速体验:创建 Bucket 和 创建 Bucket HTTP API。
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
id | text | Bucket 唯一标识,作为对象操作中的 bucketId 使用 |
name | text | Bucket 名称,长度不超过 100 个字符 |
public | boolean | 是否标记为公开 Bucket,默认 false |
file_size_limit | bigint | 单文件大小上限,单位为字节 |
allowed_mime_types | text[] | 允许上传的 MIME 类型白名单 |
owner_id | text | 创建者用户 ID,由服务端写入 |
created_at | timestamptz | 创建时间 |
updated_at | timestamptz | 更新时间 |
Public / Private 访问模型
public 是 Bucket 元数据中的公开标记,但不会自动绕过 RLS。文件是否真的可公开读取,仍由你写在 storage.objects 上的 SELECT Policy 决定。
| Bucket 形态 | 推荐配置 | 访问方式 | 适用场景 |
|---|---|---|---|
| 公 开资源 | public = true + 公开读 RLS | getPublicUrl() / 签名 URL / 下载 | Logo、公开图片、静态资源 |
| 私有资源 | public = false + owner RLS | download() / createSignedUrl() | 简历、订单附件、私人文件 |
| 团队资源 | public = false + JOIN 业务表 RLS | download() / createSignedUrl() | 团队网盘、项目附件 |
| 官方素材 | public = true + 公开读、仅 service_role 写 | getPublicUrl() | 官方图标、运营 Banner |
例如,如果希望 public = true 的 Bucket 允许匿名读取对象,可以写:
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
)
);
生产环境中通常不建议匿名写入公开 Bucket。公开读和谁能写入是两件事,应分别通过
SELECT、INSERT、UPDATE、DELETEPolicy 控制。
上传限制
Bucket 可以配置两类常用上传限制:
| 限制 | 字段 | 说明 |
|---|---|---|
| 单文件大小 | file_size_limit | 超过限制的上传会被拒绝 |
| 文件类型 | allowed_mime_types | 只允许白名单内的 MIME 类型 |
示例:限制头像 Bucket 只允许 5 MB 以内的常见图片格式:
UPDATE storage.buckets
SET
file_size_limit = 5 * 1024 * 1024,
allowed_mime_types = ARRAY['image/png', 'image/jpeg', 'image/webp']
WHERE id = 'avatars';
如果你的限制 需要依赖用户角色或业务状态,例如「普通用户最多 5 MB,管理员最多 50 MB」,可在 RLS 中结合 metadata 做更细粒度判断。详见 常见问题:是否可以在 RLS 中限制文件大小 / MIME 类型。
更新 Bucket
使用 JS SDK 更新 Bucket 配置:
const { data, error } = await app.storage.updateBucket('avatars', {
public: false,
fileSizeLimit: 10 * 1024 * 1024,
allowedMimeTypes: ['image/png', 'image/jpeg', 'image/webp'],
});
if (error) {
throw error;
}
console.log(data.updatedAt);
也可以通过 SQL 直接更新:
UPDATE storage.buckets
SET file_size_limit = 10 * 1024 * 1024
WHERE id = 'avatars';
删除 Bucket
删除 Bucket 前,请先确认 Bucket 下对象已清理完毕,并确认没有业务表继续引用该 Bucket 下的对象路径。
const { error } = await app.storage.deleteBucket('avatars');
if (error) {
throw error;
}
删除文件对象请使用 SDK / Storage API,不要直接
DELETE FROM storage.objects。直接删元数据会造成对象存储后端残留孤儿文件。详见 常见问题。
AI 友好的设计建议
为了让 AI 编程助手更准确地生成 Bucket、路径和 RLS 策略,建议在团队文档或代码注释中固定以下约定:
| 约定项 | 示例 |
|---|---|
| Bucket ID | avatars、private-files、team-files |
| 路径模板 | <uid>/avatar.png、<team_id>/<filename> |
| 权限模型 | owner_id = auth.uid()、team_members JOIN |
| 上传限制 | file_size_limit = 5242880、allowed_mime_types = ['image/png'] |
| 访问方式 | 公开资源用 getPublicUrl(),私有资源用 createSignedUrl() |
推荐在每个业务 Bucket 建立一段「Bucket 契约」说明:
Bucket: avatars
用途:用户头像
路径:<uid>/avatar.png
读取:所有用户可读
写入:仅本人可上传或覆盖自己的头像
限制:5 MB;image/png、image/jpeg、image/webp
这类结构化约定能显著降低 AI 生成错误路径、错误 Bucket 或过宽 RLS 策略的概率。