Writing

使用Cloudflare R2对象存储作为网站图床

做网站总要处理图片。文章里的截图、封面、头像,一张一张塞进代码仓库,仓库会越来越大;塞进 Vercel 之类的托管平台,还要担心流量配额——图片是流量消耗大户,一张高质量截图可能比整个站点的页面代码加起来都大。

所以图床几乎是内容型网站的标配。挑图床的时候一般看重三点:存储和流量便宜、访问速度快、能绑自己的域名。Cloudflare R2 正好都满足,其中最关键的一点是出口流量免费——对图床这种「写一次、读很多次」的场景,流量成本直接归零,存储本身只要 $0.015/GB/月。而且它兼容 S3 API,现有生态的客户端基本都能直接用。

这篇文章记录我怎么把 R2 配成这个网站的图床:存储桶配置、访问域名、CORS、防盗链,以及最后和站内编辑器集成起来的效果。

创建并配置 R2 存储桶

打开 Cloudflare 控制台,进入 R2 存储页面,点击「创建存储桶」:

屏幕截图 2025-08-20 104339.png

屏幕截图 2025-08-20 104428.png

创建完之后,可以直接在控制台拖文件上传,先手动传几张验证路径是否可访问:

屏幕截图 2025-08-20 104856.png

访问域名

存储桶里的对象需要一个公开的访问地址。有两种方式:用自己的子域名(比如 images.greatpi.dev),或者用 Cloudflare 提供的公共开发 URL。建议用自己的子域名——公共 URL 的域名不可控,绑了自己的域名以后就算换平台,图片地址也不会失效:

image.png

CORS 配置

如果图片不只是「在网页上显示」,还要被 JavaScript 读取处理(比如拿到 Canvas 里做压缩、裁剪),就得给存储桶配 CORS 策略,否则浏览器会拦跨域请求。在存储桶的 Settings → CORS 里添加一条策略,最简配置长这样:

{
  "AllowedOrigins": ["*"],
  "AllowedMethods": ["GET", "PUT"],
  "AllowedHeaders": ["*"],
  "MaxAgeSeconds": 3600
}

AllowedOrigins 如果只想放行自己的站点,可以把 * 换成具体的域名:

image.png

防盗链(Hotlink)与自定义域名

用自定义域名还有一件容易踩的坑:如果站点开了 Cloudflare 的 Hotlink 保护(防盗链),默认策略会拦掉所有不是本站来源的请求——包括你自己主域名站点发起的图片请求,因为主域名和 images 子域名是两个不同的来源。

所以要么把默认的 Hotlink 关掉:

image.png

然后在规则页面手动配置一条 Hotlink 规则,只对不符合条件的 referer 启用防盗链:

image.png

image.png

和站内编辑器集成

存储桶配好之后,剩下的工作都在代码里:站内加一个上传接口,接收图片后通过 S3 兼容 SDK 写入 R2,返回图片的公开 URL。编辑器上传图片时调用这个接口,拿到 URL 后自动生成 ![图片描述](url) 插入正文——这篇文章里的截图就是这么进来的。

总结

R2 作为图床的核心优势一句话:出口流量免费,存储按量计费,能绑自己的域名。对个人网站来说,配好一次之后基本不用再管,图片随写随传。

配置要点回顾:

  • 存储桶 + 自定义域名(或公共 URL)
  • CORS:需要 JS 处理图片时配置
  • Hotlink:和自定义域名一起用时要单独处理,别被默认策略误伤
  • 集成:上传接口写 R2 → 返回 URL → 编辑器自动插入

More