对象存储供应商对比(S3 / R2 / OSS / Supabase / MinIO)
本文对比主流对象存储供应商的关键差异,用于选型与切换。 基本用法见 基本用法(Basic Usage), 签名 URL 原理见 签名 URL(Signed URL)。 结论基于仓库内 3 个客户端原型(prototypes/ali-oss-client、 prototypes/r2-client、prototypes/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 走各自原生 SDK:
ali-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["Plans"]
n12["Knowledge"]
n13["Cloud"]
n14["对象存储基本用法(Bucket / Object / 常用操作)"]
n15["对象存储数据迁移(R2 → MinIO / 跨厂商搬迁)"]
n16["Object Storage"]
n17["挂载 Bucket 为本地文件系统(FUSE Mount)"]
n18["对象存储签名 URL(Signed URL)原理与实战"]
n19["对象存储供应商对比(S3 / R2 / OSS / Supabase / MinIO)"]
n20["Infrastructure"]
n21["Prototypes"]
n22["Research"]
n23["Better Auth 源码阅读指南"]
n24["DuckDB 环境与基本使用"]
n25["DuckDB 实战研究"]
n26["DuckDB 模拟数据"]
n27["PostgreSQL 数据用 DuckDB 加速查询"]
n28["Hollow Knight 英语主题"]
n29["英语学习 Dashboard"]
n30["English Scraps Archive"]
n31["English Scraps 使用指南"]
n32["Jellyfin 源码阅读指南"]
n33["Lux 资料整理"]
n34["Nest Commander 学习资料"]
n35["NestJS 源码阅读指南"]
n36["Protomaps 自建底图研究"]
n37["自制 PMTiles 地图(最简单例子)"]
n38["MapLibre 集成 Protomaps"]
n39["PMTiles 格式与工具链"]
n40["上海地区底图项目"]
n41["Redash 源码阅读指南"]
n42["Rust 学习计划"]
n43["shadcn/ui 源码阅读指南"]
n44["TRIP 项目核心原理与代码阅读指南"]
n1 --> n25
n6 --> n0
n6 --> n1
n6 --> n2
n6 --> n3
n6 --> n4
n6 --> n5
n6 --> n7
n6 --> n8
n6 --> n9
n6 --> n10
n6 --> n11
n6 --> n22
n12 --> n20
n13 --> n16
n14 --> n15
n14 --> n18
n14 --> n19
n14 --> n21
n15 --> n14
n15 --> n17
n15 --> n18
n15 --> n19
n16 --> n14
n16 --> n15
n16 --> n17
n16 --> n18
n16 --> n19
n17 --> n14
n17 --> n18
n17 --> n19
n18 --> n21
n19 --> n14
n19 --> n15
n19 --> n18
n19 --> n21
n20 --> n13
n21 --> n14
n21 --> n17
n21 --> n18
n21 --> n19
n21 --> n36
n22 --> n23
n22 --> n25
n22 --> n29
n22 --> n32
n22 --> n33
n22 --> n34
n22 --> n35
n22 --> n36
n22 --> n41
n22 --> n42
n22 --> n43
n22 --> n44
n24 --> n26
n25 --> n1
n25 --> n22
n25 --> n24
n25 --> n26
n25 --> n27
n26 --> n24
n26 --> n27
n27 --> n25
n27 --> n26
n28 --> n31
n29 --> n28
n29 --> n30
n29 --> n31
n31 --> n29
n31 --> n30
n36 --> n8
n36 --> n37
n36 --> n38
n36 --> n39
n36 --> n40
n37 --> n39
n38 --> n21
n38 --> n40
n39 --> n37
n39 --> n40
n40 --> n38
n40 --> n39
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/scraps/plans/" "Plans"
click n12 "../../../../" "Knowledge"
click n13 "../../" "Cloud"
click n14 "../basic-usage/" "对象存储基本用法(Bucket / Object / 常用操作)"
click n15 "../data-migration/" "对象存储数据迁移(R2 → MinIO / 跨厂商搬迁)"
click n16 "../" "Object Storage"
click n17 "../mount-bucket/" "挂载 Bucket 为本地文件系统(FUSE Mount)"
click n18 "../signed-url/" "对象存储签名 URL(Signed URL)原理与实战"
click n19 "./" "对象存储供应商对比(S3 / R2 / OSS / Supabase / MinIO)"
click n20 "../../../" "Infrastructure"
click n21 "../../../../../prototypes/" "Prototypes"
click n22 "../../../../../research/" "Research"
click n23 "../../../../../research/topics/better-auth/" "Better Auth 源码阅读指南"
click n24 "../../../../../research/topics/duckdb/basic-usage/" "DuckDB 环境与基本使用"
click n25 "../../../../../research/topics/duckdb/" "DuckDB 实战研究"
click n26 "../../../../../research/topics/duckdb/mock-data/" "DuckDB 模拟数据"
click n27 "../../../../../research/topics/duckdb/postgresql-acceleration/" "PostgreSQL 数据用 DuckDB 加速查询"
click n28 "../../../../../research/topics/english/hollow-knight/" "Hollow Knight 英语主题"
click n29 "../../../../../research/topics/english/" "英语学习 Dashboard"
click n30 "../../../../../research/topics/english/scraps/archive/" "English Scraps Archive"
click n31 "../../../../../research/topics/english/scraps/" "English Scraps 使用指南"
click n32 "../../../../../research/topics/jellyfin/" "Jellyfin 源码阅读指南"
click n33 "../../../../../research/topics/lux/" "Lux 资料整理"
click n34 "../../../../../research/topics/nest-commander/" "Nest Commander 学习资料"
click n35 "../../../../../research/topics/nestjs/" "NestJS 源码阅读指南"
click n36 "../../../../../research/topics/protomaps/" "Protomaps 自建底图研究"
click n37 "../../../../../research/topics/protomaps/make-own-map/" "自制 PMTiles 地图(最简单例子)"
click n38 "../../../../../research/topics/protomaps/maplibre/" "MapLibre 集成 Protomaps"
click n39 "../../../../../research/topics/protomaps/pmtiles/" "PMTiles 格式与工具链"
click n40 "../../../../../research/topics/protomaps/shanghai-map/" "上海地区底图项目"
click n41 "../../../../../research/topics/redash/" "Redash 源码阅读指南"
click n42 "../../../../../research/topics/rust/" "Rust 学习计划"
click n43 "../../../../../research/topics/shadcn-ui/" "shadcn/ui 源码阅读指南"
click n44 "../../../../../research/topics/trip/" "TRIP 项目核心原理与代码阅读指南"
Links (4)