文件存储(Storage)
场景介绍
本章节介绍华为云RDS Supabase的文件存储(Storage)功能,涵盖控制台配置、文件管理、SDK操作及安全策略设置。
文件存储底层对接华为云OBS对象存储,提供兼容S3标准的对象存储服务,即插即用。用户无需单独购买第三方存储、自建文件存储服务器,也无需承担底层运维。OBS对象存储按需计费,费用依据存储容量、请求次数与公网流量等维度产生,详见华为云OBS计费说明。
RDS Supabase提供一站式托管,文件上传、下载、查看由OBS桶承载,并通过灵活安全的API与SDK完成读写。
支持大文件高性能上传下载,结合Auth的行级安全(RLS)策略,可对存储桶实现精细的文件访问权限控制,以一条策略界定“谁能看、谁能传、谁能删”。
相关概念
| 概念 | 说明 |
|---|---|
| 存储桶(Bucket) | 存储文件的顶层容器,可设为公开或私有。每个存储桶对应华为云OBS桶中的一个子文件夹(子目录)。 |
| 文件夹 | 存储桶内用于组织文件的层级结构。 |
| 文件 | 图片、文档等二进制资源,存放于OBS对象存储,避免大文件占用数据库。 |
| 后端存储 | 文件存储功能底层对接华为云OBS对象存储,文件上传、下载、查看等均由OBS桶承载。 |
存储桶与OBS桶的映射关系:
1个华为云OBS桶承载1个RDS Supabase实例的全部存储,每个Supabase存储桶对应OBS桶下的1个子目录。
下面以电商场景的两个存储桶为例:product-images(公开,存放产品图片)与product-specs(私有,存放产品规格文档)。后续控制台操作、SDK示例与安全策略均围绕这两个桶展开。可对照本节映射关系理解各操作作用于OBS桶下的哪个子目录。
OBS桶(华为云) ├── product-images/ ← 公开存储桶(产品图片) └── product-specs/ ← 私有存储桶(产品规格文档)
文件类型与大小约束:
Storage支持上传任意类型的二进制文件(图片、文档、音视频、压缩包等),可按存储桶通过MIME类型限制允许的文件类型。
单文件大小上限可按存储桶配置,超大文件建议分片上传。
前提条件
| 条件 | 说明 |
|---|---|
| 华为云实名认证 | 使用存储功能前必须完成,否则文件存储功能底层无法接入OBS对象存储服务。 |
| OBS桶与AK/SK | 在华为云OBS控制台创建OBS桶,在IAM控制台创建具有OBS权限的AK/SK(建议遵循最小权限原则)。 |
| 网络可达 | 客户端需能访问Supabase应用的访问IP与访问端口。 |
| 同区域 | OBS桶建议与RDS Supabase实例处于同一区域。 |
功能启用
文件存储功能底层对接华为云OBS,使用前需在华为云管理控制台完成存储功能启用配置。简要流程:
- 在华为云OBS控制台创建OBS桶,并在IAM控制台创建具有OBS权限的AK/SK。
- 在RDS Supabase控制台应用详情页的基础信息区域填入OBS桶名、AK、SK并启用。
详细操作步骤请参见开启或关闭Storage存储配置。
经文件存储功能托管(创建)的文件及目录,业务使用期间不得直连OBS桶进行修改、删除等管理操作,须通过Supabase Storage API完成,避免Supabase侧文件元数据不一致。
通过控制台管理文件
- 创建存储桶
在控制台创建存储桶,相当于在OBS桶下新建一个子目录(详见相关概念中的映射关系),用于按业务隔离存放文件。
- 登录Supabase Dashboard控制台。
- 在左侧导航栏,选择“Storage”,单击“New bucket”。 图1 Supabase Dashboard创建存储桶Bucket指引
- 在创建存储桶页面,填写相关配置项。 图2 Supabase Dashboard创建存储桶Bucket配置项界面
- Bucket name:输入业务桶名称(对应OBS桶下的子目录名)。
- Public bucket配置示例:
- product-images(存放产品图片):开启“Public bucket”开关。
- product-specs(存放产品规格文档):不开启“Public bucket”开关。
- 文件大小限制和MIME类型配置示例:
- product-images:文件大小限制10MB,允许MIME类型image/png, image/jpeg, image/webp, image/gif。
- product-specs:文件大小限制50MB,允许MIME类型application/pdf。
- 单击“Create”完成创建。 图3 Bucket桶列表
- 上传和管理文件
- 单击目标存储桶,进入详情页。
- 单击“Create folder”,创建文件存储子目录。 图4 Supabase Dashboard创建存储桶文件夹入口
- 单击“Upload files”,上传文件。 图5 Supabase Dashboard上传文件
- 在文件右侧菜单,可进行下载、获取URL、移动、删除等操作。
安全策略设置
Storage Policies基于PostgreSQL的行级安全(RLS)机制。storage schema的RLS需处于启用状态,策略才能生效。
- 登录Supabase Dashboard控制台。
- 在左侧导航栏,选择“Storage”,进入存储管理页面,再单击“Policies”页签。 图6 Supabase Dashboard存储桶安全策略配置列表
- 选择要操作的存储桶Bucket,单击“New Policy”,选择使用模板或自定义。 图7 Supabase Dashboard存储桶新增自定义安全策略
- 配置策略名称、允许操作、目标角色。
- product-images(公开桶,允许公共读取):
- 策略名称:Public read for product-images
- 操作类型:允许操作SELECT
- 目标角色:anon
- 策略定义:bucket_id = 'product-images'
- product-specs(私有桶,仅认证用户访问自己的文件夹):
- 策略名称:Authenticated access for product-specs
- 操作类型:允许操作INSERT、SELECT
- 目标角色:authenticated
- 策略定义:bucket_id = 'product-specs' AND auth.uid()::text = (storage.foldername(name))[1]
- product-images(公开桶,允许公共读取):
- 单击“Save policy”。
- 允许对指定存储桶的公共读取
- 仅允许认证用户访问自己的文件夹 示例场景:为产品规格文档桶product-specs设置用户隔离,登录用户只能读写以自己用户ID命名的文件夹,看不到也改不了他人的规格文档,适用于各用户私密文档存放。
-- 上传:仅在自己的文件夹内 CREATE POLICY "Authenticated upload in user folder" ON storage.objects FOR INSERT TO authenticated WITH CHECK(bucket_id = 'product-specs' AND auth.uid()::text = (storage.foldername(name))[1]); -- 读取:仅在自己的文件夹内 CREATE POLICY "Authenticated read in user folder" ON storage.objects FOR SELECT TO authenticated USING(bucket_id = 'product-specs' AND auth.uid()::text = (storage.foldername(name))[1]);
以上示例假设存储桶内以用户ID(auth.uid())作为顶层文件夹名,按文件夹隔离访问。
通过SDK操作文件
通过SDK操作前请确保目标存储桶已配置相应安全策略,公开存储桶的读取无需策略。
以下操作以product-images(公开,存放产品图片)和product-specs(私有,存放产品规格文档)两个存储桶为例。
- 创建存储桶
示例场景:用代码创建存储桶,等于在OBS桶下新建一个按业务隔离的子目录。电商场景分别建公开的产品图片桶与私有的产品规格文档桶,使图片可被公开浏览、规格文档仅限授权访问。
// 创建公开存储桶 await supabase.storage.createBucket('product-images', { public: true }) // 创建私有存储桶 await supabase.storage.createBucket('product-specs', { public: false }) - 上传文件
示例场景:将本地文件上传到指定桶路径。运营在后台为新品上传图片时,前端选择图片上传至product-images桶,成功后图片即落入OBS,可供商品详情页直接展示。
const file = event.target.files[0] const { data, error } = await supabase.storage .from('product-images') .upload('ecs/console.png', file, { cacheControl: '3600', upsert: false, }) if (error) { console.error('上传失败', error) return } - 下载文件
示例场景:从桶中取回文件内容。需要在前端预览或处理文件时(如客服查看用户规格文档),调用下载拿到文件数据并转为可用URL,供页面渲染或进一步处理。
const { data, error } = await supabase.storage .from('product-images') .download('ecs/console.png') // data是Blob对象 const url = URL.createObjectURL(data) - 获取公开URL/签名URL
示例场景:取得文件的访问链接。公开桶图片用公开URL直接嵌入页面展示;私有桶敏感文档生成限时签名URL,既允许指定对象临时查看,又不长期暴露文件地址。
// 公开存储桶 — 直接获取URL const { data } = supabase.storage .from('product-images') .getPublicUrl('ecs/console.png') // URL格式:https://{访问IP}:{访问端口}/storage/v1/object/public/product-images/ecs/console.png // 访问IP、访问端口请在准备工作章节获取 // 私有存储桶 — 生成临时签名URL(60秒有效) const { data, error } = await supabase.storage .from('product-specs') .createSignedUrl('obs/pricing.pdf', 60)getPublicUrl返回的URL仅在存储桶设为public时可直接访问;私有存储桶需通过createSignedUrl生成临时签名URL。
- 列出文件
示例场景:列出某桶某目录下的文件清单。后台管理商品图片库时,分页列出某产品目录下全部图片,供运营浏览、挑选、管理。
const { data, error } = await supabase.storage .from('product-images') .list('ecs', { limit: 100, sortBy: { column: 'name', order: 'asc' } }) - 删除文件
示例场景:从桶中移除文件。产品下架或图片替换时删除旧图,释放空间并避免脏数据残留;支持一次删除多个文件。
await supabase.storage .from('product-images') .remove(['ecs/console.png', 'ecs/detail.png'])