Cloudflare R2 + Pages 零成本图床

R2 免费层 10GB 存储 + 免出口流量费,配 Pages Functions 上传 —— 自己搭一个不花一分钱的图床。

← 返回教程列表

分类:实测教程 · 最后更新:2026-09-30 · 适用:中文个人开发者

Cloudflare R2 是 Cloudflare 的对象存储(对标 AWS S3),最大卖点是 「免出口流量费」——上传下载都不按流量扣钱(AWS S3 出口流量是出了名地贵)。对个人站长、图床、小产品存储来说,这点直接省掉最大的隐性成本。再配合 Pages Functions(本站首页就是 Cloudflare Pages 托管的),前端上传 → 函数转存 R2,一套下来零成本。

本篇是实测向教程,重点在「免费层给多少」和「哪里会踩坑」。控制台入口:dash.cloudflare.com。您需要有一个 Cloudflare 账号(本站域名就托管在这),但开 R2 必须绑一张信用卡,详见踩坑 1。

一、免费层额度清单(先看清边界)

R2 的免费额度叫 Free Tier,下面这些量级是 2026 年实测到的,做图床前心里先有数:

资源免费层额度说明
存储空间10 GB含对象本身,超出 $0.015/GB·月
出口流量(Egress)免费这是 R2 最大卖点,下载不收费
A 类操作(写/列)1,000 万次 / 月上传、列举算 A 类,正常图床用不完
B 类操作(读)100 万次 / 月下载读取算 B 类,免费层偏紧,见踩坑 4
每次对象大小上限300 MB(单对象)单张图远小于此,图床足够
⚠️ 踩坑 1 — 开 R2 必须绑卡,但不一定扣费。R2 要求账号绑定一张有效信用卡(或 PayPal)才能启用,免费层 10GB 内不扣钱,但要注意:绑卡后如果误开其他付费服务(如 Workers 超出、R2 超量)才会扣。对策:绑一张额度可控的卡,并定期看 Billing 页。

二、适合用它做什么

三、开通全流程(实测步骤)

  1. 进入 R2 控制台。左侧菜单找到 R2(若没看到,先在 Account Home 点开 R2 并绑卡激活)。
  2. 创建存储桶(Bucket)。点 Create bucket,填桶名(全局唯一,如 my-img-bed),区域选 auto(自动就近)。是否公开这里先选 Private(稍后单独配公开读,见踩坑 3),更稳妥。
  3. 拿到桶信息。进桶后,记下 Bucket name 和 Account ID(在右侧 API 信息里),上传代码要用。
  4. 建 API 令牌。进桶 Manage R2 API tokens → Create API token,权限选 Object Read & Write,作用域限定这个桶。保存好生成的 Access Key ID 和 Secret Access Key(只显示一次)。
  5. 建一个 Pages 项目(或复用本站)。图床前端 + 上传函数跑在 Cloudflare Pages 上。可在现有 keting.eu.org 仓库加一个 /imgbed 路径,或单独建项目。本篇示例走「独立函数」最简形态。
  6. 把密钥配成环境变量。Pages 项目 Settings → Environment variables 加:R2_ACCOUNT_ID、R2_BUCKET、R2_ACCESS_KEY_ID、R2_SECRET_ACCESS_KEY。切勿把 Secret 写进前端代码。

四、最小可跑示例

一个最简单的上传函数(/api/upload.js,Pages Functions 约定路径):

export async function onRequestPost({ request, env }) {
  const form = await request.formData()
  const file = form.get('file')
  if (!file) return new Response('no file', { status: 400 })

  // 用原文件名 + 时间戳避免覆盖
  const key = Date.now() + '-' + file.name
  await env.MY_BUCKET.put(key, file.stream())

  // 公开读地址(需桶设为 public,见踩坑 3)
  const url = `https://pub-${env.R2_ACCOUNT_ID}.r2.dev/${key}`
  return new Response(JSON.stringify({ url }), {
    headers: { 'content-type': 'application/json' }
  })
}

函数里用到的 env.MY_BUCKET 需要在 wrangler.toml(或 Pages 的 R2 绑定界面)把存储桶绑成这个名字。前端只要一个文件输入框 POST 到 /api/upload 即可。

五、7 个真实踩坑提醒

⚠️ 踩坑 2 — 公开读要显式开。R2 默认 Private,直接拼 r2.dev 地址会 403。两种公开方式:① 桶设为 Public(最简单,适合纯图床);② 用 Cloudflare 自定义域 + r2.dev 关闭只允许自定义域。图床选 ① 最省事。
⚠️ 踩坑 3 — r2.dev 仅用于开发,生产建议绑自定义域。免费即可在桶的 Settings → Public development URL 拿到 pub-xxx.r2.dev,但 Cloudflare 不保证其 SLA,量起来后请在 Cloudflare 侧绑一个自己的子域(如 img.yourdomain.com)。
⚠️ 踩坑 4 — B 类操作(读)免费层只有 100 万次 / 月。看似多,但图床被热帖刷、或页面里塞了几百张图,一个月很容易冲到。超出按量计费。对策:给图片加浏览器缓存头、控制单页图片数;真要高频读,把热门图转 CDN 缓存。
⚠️ 踩坑 5 — 密钥别进前端。上传用的 Secret Access Key 只能在 Pages Functions(服务端)里用,绝不可暴露到浏览器。一旦泄露,别人能读写您的整个桶。建议用「仅限该桶 + 读写」的最小权限令牌,并定期轮换。
⚠️ 踩坑 6 — 文件名冲突会覆盖。上面示例用时间戳前缀规避;若您想保留原文件名,需先 list 检查是否已存在,否则同名直接覆盖、不可自动恢复(见踩坑 7)。
⚠️ 踩坑 7 — R2 没有「回收站」。对象删除是立即、不可逆的,不像 Supabase 有 7 天宽限。删错只能从备份恢复。重要图床建议:开 R2 的 Event notifications 或定期导出清单做异地备份。
💡 组合拳:R2(大文件/图片存储,免流量费)+ Cloudflare Pages(本站前端,免费托管)+ Supabase(用户/元数据,见本站另一篇)。三者叠加 = 一个几乎零成本的全栈小产品底座。本系列教程正是教您把这套矩阵用起来。

六、什么时候该付费

出现下面任一信号,说明免费层到顶了:存储超 10GB、B 类读取远超 100 万次/月、需要更强的合规/加密、或要把 R2 当生产数据库备份。届时 R2 按量计费很透明(存储 $0.015/GB·月、免出口),迁移也只是改桶名,无痛。

← 返回教程列表