Skip to content

对象存储供应商对比(S3 / R2 / OSS / Supabase / MinIO)

本文对比主流对象存储供应商的关键差异,用于选型与切换。 基本用法见 基本用法(Basic Usage), 签名 URL 原理见 签名 URL(Signed URL)。 结论基于仓库内 3 个客户端原型(prototypes/ali-oss-clientprototypes/r2-clientprototypes/supabase-storage-client)的端到端实测, 其中 r2-client 的本地测试跑在 MinIO 上。

概览对比表

维度 AWS S3(参照系) Cloudflare R2 阿里云 OSS Supabase Storage MinIO
定位 云对象存储事实标准 Cloudflare 边缘对象存储 阿里云对象存储 Postgres 生态的存储附件 自托管 S3 兼容服务器
API 形态 S3 原生 S3 兼容 原生 API(非 S3) REST API(可选 S3 协议) S3 兼容
常用 SDK @aws-sdk/client-s3 @aws-sdk/client-s3 ali-oss @supabase/supabase-js @aws-sdk/client-s3 / mc
签名 URL Presigned(SigV4) Presigned(SigV4) 签名 URL(V1/V4) Signed URL(服务端过期) Presigned(S3 兼容)
Content-Type 是否被签名 是(V1)
凭证 IAM User / Role R2 API Token RAM AccessKey / STS anon key + service_role root / 自定义用户
权限模型 IAM Policy Token 权限层级 RAM Policy Postgres RLS IAM 风格 Policy
region 必选 auto(忽略) 必选 无(hosted)/ 固定本地 us-east-1 默认
地址风格 virtual-hosted virtual-hosted virtual-hosted REST 路径 forcePathStyle
本地开发 LocalStack(第三方) 无官方 → 用 MinIO 无官方 emulator supabase start 全栈 本身就是本地服务器
免费额度 12 个月免费层 免费存储额度 + 零出口流量费 新用户免费额度(按量计费) 免费层 开源(Apache 2.0)

关键差异

1. S3 兼容 = 生态红利(最大的差异)

  • R2 与 MinIO 走 S3 兼容 API:直接用标准 @aws-sdk/client-s3,只需改 endpoint / credentials / region / forcePathStyle 四个配置即可切换,业务代码 零改动
  • OSS 与 Supabase 走各自原生 SDKali-oss@supabase/supabase-js, 方法名与返回结构不通用,换厂商要重写客户端
  • 意义:选 S3 兼容供应商,SDK、工具(aws cli、mc)、生态组件(CDN、图片处理) 全部通用,数据搬迁也可用 S3 兼容工具

2. 签名 URL 的差异

差异 OSS(V1) S3 / R2 / MinIO Supabase
Content-Type 绑定 绑定:消费端必须带与签发时相同的 Content-Type,否则 403 SignatureDoesNotMatch 不绑定:裸 curl PUT 即可(传了只影响对象元数据) 不绑定
过期机制 客户端签名过期(URL 带 Expires) 客户端签名过期(X-Amz-Expires) 服务端决定(上传 URL 无客户端 expiry,token 存服务端)
上传 URL 覆盖 直接覆盖 直接覆盖 upsert: true,否则 Duplicate
  • OSS 的坑最常见:生成 PUT 签名 URL 时必须带上 Content-Type,消费端必须原样 发送(signed-url.md 有完整的 curl 验证)
  • Supabase 签名上传 URL 没有客户端过期时间,有效期由 Storage API 服务端决定 (不同版本默认值不同)

3. 权限模型(Permission Model)

  • 身份策略(OSS / AWS):RAM / IAM 用户 + Policy 绑定,粒度到 bucket / 操作; 生产建议用 STS 临时凭证或角色替代长期 AccessKey
  • Token 权限(R2):R2 API Token 自带权限范围 —— Admin Read & Write 才能列桶 / 建桶 / 删桶;Object Read & Write 只能做对象级操作 (ListBuckets 会 403);生产应把 Token 范围缩到单个 bucket
  • 数据库级 RLS(Supabase):权限用 Postgres RLS Policy 表达;anon key 是 公开 JWT(设计上就进浏览器),service_role key 绕过 RLS、必须留在 服务端。注意:新版 Storage 默认没有任何 RLS policy,所有非 service_role 请求都会被拒 —— 必须先建 policy 才能用 anon key 访问

4. Region 与 Endpoint

  • OSS:region 必选(如 oss-cn-hangzhou),endpoint 由 region 派生
  • R2:endpoint 由 Account ID 派生 (https://<ACCOUNT_ID>.r2.cloudflarestorage.com),region 传 auto(被忽略)
  • MinIO:本地无虚拟主机 DNS,必须 forcePathStyle: true,region 用默认 us-east-1
  • Supabase:本地全栈固定 http://127.0.0.1:64321(API 代理端口), Storage 挂在 /storage/v1

5. 本地开发与测试

  • MinIO 是 S3 生态的本地标准:没有官方 R2 / AWS 本地 emulator 时,Docker 起一个 MinIO 即可测所有 S3 兼容供应商(r2-client 原型就是这么测的,代码零 改动);数据存在 named volume 里可持久化
  • Supabase 自带本地全栈supabase start 拉起 Postgres + PostgREST + Storage + Auth + Studio,anon key 可自动从 supabase status 读取
  • OSS 没有官方 emulator:本地测试最麻烦,只能连真实服务(或依赖第三方模拟)

6. 免费额度与出口流量

  • R2 的杀手锏:零出口流量费(egress free) —— 对"下载多"的场景(图床、 静态资源)成本优势明显;另有免费存储额度
  • OSS:按量计费(存储 + 流量 + 请求数),新用户有免费额度
  • Supabase:免费层(带存储配额),超出收费
  • MinIO:开源免费,自托管成本只有机器

选型建议

场景 推荐 理由
需要 S3 生态兼容 / 多供应商迁移 R2 / MinIO / AWS 标准 SDK 通用,切换成本低
下载流量大、成本敏感(图床 / CDN 资源) R2 零出口流量费
阿里云生态(ECS 同地域内网、RAM、STS) OSS 内网免流量、与云生态整合
已有 Postgres / Supabase 应用 Supabase Storage 与 Auth / RLS 深度集成,无需额外存储服务
本地开发 / CI 测试 S3 兼容代码 MinIO Docker 一键起,行为与 S3 一致
需要细粒度、可追溯的访问控制 任一 + 签名 URL 权限在签名 URL 层收敛(见 signed-url.md)

一句话结论:默认选 S3 兼容(R2 / MinIO),生态红利最大;只有深度绑定 某个平台(阿里云、Supabase)时才用其原生 SDK。

参考

Backlinks (5)
flowchart LR
  n0["AI"]
  n1["Database"]
  n2["Dev Tools"]
  n3["Emoji"]
  n4["Frontend"]
  n5["Game Dev"]
  n6["Collection"]
  n7["Languages"]
  n8["Maps"]
  n9["Media"]
  n10["Monitor"]
  n11["Study Materials"]
  n12["Plans"]
  n13["Storage"]
  n14["Database"]
  n15["Knowledge"]
  n16["Cloud"]
  n17["对象存储基本用法(Bucket / Object / 常用操作)"]
  n18["对象存储数据迁移(R2 → MinIO / 跨厂商搬迁)"]
  n19["Object Storage"]
  n20["挂载 Bucket 为本地文件系统(FUSE Mount)"]
  n21["对象存储签名 URL(Signed URL)原理与实战"]
  n22["对象存储供应商对比(S3 / R2 / OSS / Supabase / MinIO)"]
  n23["Infrastructure"]
  n24["Prototypes"]
  n25["Research"]
  n26["Better Auth 源码阅读指南"]
  n27["DuckDB 环境与基本使用"]
  n28["DuckDB 实战研究"]
  n29["DuckDB 模拟数据"]
  n30["PostgreSQL 数据用 DuckDB 加速查询"]
  n31["Hollow Knight 英语主题"]
  n32["英语学习 Dashboard"]
  n33["English Scraps Archive"]
  n34["English Scraps 使用指南"]
  n35["Jellyfin 源码阅读指南"]
  n36["Lux 资料整理"]
  n37["Nest Commander 学习资料"]
  n38["NestJS 源码阅读指南"]
  n39["Protomaps 自建底图研究"]
  n40["自制 PMTiles 地图(最简单例子)"]
  n41["MapLibre 集成 Protomaps"]
  n42["PMTiles 格式与工具链"]
  n43["上海地区底图项目"]
  n44["Redash 源码阅读指南"]
  n45["Rust 学习计划"]
  n46["shadcn/ui 进阶使用"]
  n47["shadcn/ui 组件添加与基本使用"]
  n48["shadcn/ui 实用研究(从环境到基本使用)"]
  n49["TRIP 项目核心原理与代码阅读指南"]
  n1 --> n28
  n1 --> n30
  n4 --> n48
  n6 --> n0
  n6 --> n1
  n6 --> n2
  n6 --> n3
  n6 --> n4
  n6 --> n5
  n6 --> n7
  n6 --> n8
  n6 --> n9
  n6 --> n10
  n6 --> n11
  n6 --> n12
  n6 --> n13
  n6 --> n25
  n15 --> n14
  n15 --> n23
  n16 --> n19
  n17 --> n18
  n17 --> n21
  n17 --> n22
  n17 --> n24
  n18 --> n17
  n18 --> n20
  n18 --> n21
  n18 --> n22
  n19 --> n17
  n19 --> n18
  n19 --> n20
  n19 --> n21
  n19 --> n22
  n20 --> n17
  n20 --> n21
  n20 --> n22
  n21 --> n24
  n22 --> n17
  n22 --> n18
  n22 --> n21
  n22 --> n24
  n23 --> n16
  n24 --> n17
  n24 --> n20
  n24 --> n21
  n24 --> n22
  n24 --> n39
  n25 --> n26
  n25 --> n28
  n25 --> n32
  n25 --> n35
  n25 --> n36
  n25 --> n37
  n25 --> n38
  n25 --> n39
  n25 --> n44
  n25 --> n45
  n25 --> n48
  n25 --> n49
  n27 --> n29
  n28 --> n1
  n28 --> n25
  n28 --> n27
  n28 --> n29
  n28 --> n30
  n29 --> n27
  n29 --> n30
  n30 --> n28
  n30 --> n29
  n31 --> n34
  n32 --> n31
  n32 --> n33
  n32 --> n34
  n34 --> n32
  n34 --> n33
  n39 --> n8
  n39 --> n40
  n39 --> n41
  n39 --> n42
  n39 --> n43
  n40 --> n42
  n41 --> n24
  n41 --> n43
  n42 --> n40
  n42 --> n43
  n43 --> n41
  n43 --> n42
  n46 --> n47
  n47 --> n46
  n48 --> n4
  n48 --> n25
  n48 --> n46
  n48 --> n47
  click n0 "../../../../../collection/ai/" "AI"
  click n1 "../../../../../collection/database/" "Database"
  click n2 "../../../../../collection/dev-tools/" "Dev Tools"
  click n3 "../../../../../collection/emoji/" "Emoji"
  click n4 "../../../../../collection/frontend/" "Frontend"
  click n5 "../../../../../collection/game-dev/" "Game Dev"
  click n6 "../../../../../collection/" "Collection"
  click n7 "../../../../../collection/languages/" "Languages"
  click n8 "../../../../../collection/maps/" "Maps"
  click n9 "../../../../../collection/media/" "Media"
  click n10 "../../../../../collection/monitor/" "Monitor"
  click n11 "../../../../../collection/reading/" "Study Materials"
  click n12 "../../../../../collection/scraps/plans/" "Plans"
  click n13 "../../../../../collection/storage/" "Storage"
  click n14 "../../../../database/" "Database"
  click n15 "../../../../" "Knowledge"
  click n16 "../../" "Cloud"
  click n17 "../basic-usage/" "对象存储基本用法(Bucket / Object / 常用操作)"
  click n18 "../data-migration/" "对象存储数据迁移(R2 → MinIO / 跨厂商搬迁)"
  click n19 "../" "Object Storage"
  click n20 "../mount-bucket/" "挂载 Bucket 为本地文件系统(FUSE Mount)"
  click n21 "../signed-url/" "对象存储签名 URL(Signed URL)原理与实战"
  click n22 "./" "对象存储供应商对比(S3 / R2 / OSS / Supabase / MinIO)"
  click n23 "../../../" "Infrastructure"
  click n24 "../../../../../prototypes/" "Prototypes"
  click n25 "../../../../../research/" "Research"
  click n26 "../../../../../research/topics/better-auth/" "Better Auth 源码阅读指南"
  click n27 "../../../../../research/topics/duckdb/basic-usage/" "DuckDB 环境与基本使用"
  click n28 "../../../../../research/topics/duckdb/" "DuckDB 实战研究"
  click n29 "../../../../../research/topics/duckdb/mock-data/" "DuckDB 模拟数据"
  click n30 "../../../../../research/topics/duckdb/postgresql-acceleration/" "PostgreSQL 数据用 DuckDB 加速查询"
  click n31 "../../../../../research/topics/english/hollow-knight/" "Hollow Knight 英语主题"
  click n32 "../../../../../research/topics/english/" "英语学习 Dashboard"
  click n33 "../../../../../research/topics/english/scraps/archive/" "English Scraps Archive"
  click n34 "../../../../../research/topics/english/scraps/" "English Scraps 使用指南"
  click n35 "../../../../../research/topics/jellyfin/" "Jellyfin 源码阅读指南"
  click n36 "../../../../../research/topics/lux/" "Lux 资料整理"
  click n37 "../../../../../research/topics/nest-commander/" "Nest Commander 学习资料"
  click n38 "../../../../../research/topics/nestjs/" "NestJS 源码阅读指南"
  click n39 "../../../../../research/topics/protomaps/" "Protomaps 自建底图研究"
  click n40 "../../../../../research/topics/protomaps/make-own-map/" "自制 PMTiles 地图(最简单例子)"
  click n41 "../../../../../research/topics/protomaps/maplibre/" "MapLibre 集成 Protomaps"
  click n42 "../../../../../research/topics/protomaps/pmtiles/" "PMTiles 格式与工具链"
  click n43 "../../../../../research/topics/protomaps/shanghai-map/" "上海地区底图项目"
  click n44 "../../../../../research/topics/redash/" "Redash 源码阅读指南"
  click n45 "../../../../../research/topics/rust/" "Rust 学习计划"
  click n46 "../../../../../research/topics/shadcn-ui/advanced/" "shadcn/ui 进阶使用"
  click n47 "../../../../../research/topics/shadcn-ui/components/" "shadcn/ui 组件添加与基本使用"
  click n48 "../../../../../research/topics/shadcn-ui/" "shadcn/ui 实用研究(从环境到基本使用)"
  click n49 "../../../../../research/topics/trip/" "TRIP 项目核心原理与代码阅读指南"
Links (4)