
使用 Cloudflare Workers 构建免费图床:控制 R2 成本并使用缓存
Cloudflare R2 确实是个好东西,10GB 免费空间加上每月一千万次免费 Class B 操作,比某 AWS 不知道高到哪里去了。但是有个坑:公开存储桶的请求次数是不设防的。万一有人恶意刷你的桶,或者你的资源突然火了被疯狂访问,账单能直接让你破产。
如何用 Cloudflare Worker 给 R2 图床加个安全阀
解决方案
其实原理很简单:用 Worker 当中间人。把存储桶设为私有,然后通过 Worker 来代理访问。这样有两个好处:
- Worker 免费版每天 10 万次请求限制成了天然防火墙
- 还能顺手加个缓存,减少实际访问 R2 的次数
具体操作
第一步:创建 R2 存储桶
- 进 Cloudflare 控制台
- 找到 R2 页面
- 点” 创建存储桶”
- 起个名字(比如
my-private-bucket
) - 重要:别勾选” 公开访问”
第二步:创建 Worker
参考地址 使用 Cloudflare Worker 的免费账户限制 R2 的支出(新版本更新使用 D1 数据库限制次数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| export default { async fetch(request, env) { const path = decodeURIComponent(new URL(request.url).pathname.slice(1));
if (!path) { return new Response("Not Found", { status: 404 }); } try { const file = await env.OPCT.get(path); if (!file) { return new Response("Not Found", { status: 404 }); } const headers = new Headers(); headers.set('Content-Type', file.httpMetadata?.contentType || 'application/octet-stream'); return new Response(file.body, { headers }); } catch (error) { return new Response("Server Error", { status: 500 }); } } }
|
第三步:绑定资源
- 在 Worker 设置里找到” 资源绑定”
- 添加新绑定:
- 变量名:
OPCT
(随便起,但代码里要用一样的) - 类型:R2 存储桶
- 选择你刚创建的存储桶
注意事项
- Worker 位置:保持默认就行,选” 智能路由” 反而可能把请求都路由到存储桶所在区域
为什么需要缓存
最开始我用的无缓存版本,在讨论帖我使用 CloudflareWorker 做地球图片后端,我试图使用 Cloudflare 缓存但 cf-cache-status 字段缺失没有缓存中发现我的图床也一样,响应头里没有 cf-cache-status
,说明完全没走缓存。查了文档才知道要用 caches.default
这个 API。加了缓存之后:
- 重复请求不会打到 R2
- 响应速度更快
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| export default { async fetch(request, env) { const path = decodeURIComponent(new URL(request.url).pathname.slice(1));
if (!path) { return new Response("Not Found", { status: 404 }); }
const cache = caches.default; try { let response = await cache.match(request); if (response) { return response; } const file = await env.OPCT.get(path); if (!file) { return new Response("Not Found", { status: 404 }); } const headers = new Headers(); headers.set('Content-Type', file.httpMetadata?.contentType || 'application/octet-stream'); headers.set('Cache-Control', 'public, max-age=3600'); response = new Response(file.body, { headers }); await cache.put(request, response.clone()); return response; } catch (error) { return new Response("Server Error", { status: 500 }); } } }
|
其他方案
看到有人用 D1 数据库做访问次数限制 使用 Cloudflare Worker 的免费账户限制 R2 的支出(新版本更新使用 D1 数据库限制次数) ,适合更精细的控制。但我觉得对于普通用途,Worker 的每日 10 万次限制 + 缓存已经够用了
参考链接
- 使用 Cloudflare Worker 的免费账户限制 R2 的支出(新版本更新使用 D1 数据库限制次数)
- 我使用 CloudflareWorker 做地球图片后端,我试图使用 Cloudflare 缓存但 cf-cache-status 字段缺失没有缓存
- 使用 Cloudflare Workers 中的 Cache API 来全局缓存,减少 KV 的读写,可跨 worker 缓存