
使用 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 | export default { |
第三步:绑定资源
- 在 Worker 设置里找到” 资源绑定”
- 添加新绑定:
- 变量名:
OPCT
(随便起,但代码里要用一样的) - 类型:R2 存储桶
- 选择你刚创建的存储桶
- 变量名:
注意事项
- Worker 位置:保持默认就行,选” 智能路由” 反而可能把请求都路由到存储桶所在区域
为什么需要缓存
最开始我用的无缓存版本,在讨论帖我使用 CloudflareWorker 做地球图片后端,我试图使用 Cloudflare 缓存但 cf-cache-status 字段缺失没有缓存中发现我的图床也一样,响应头里没有 cf-cache-status
,说明完全没走缓存。查了文档才知道要用 caches.default
这个 API。加了缓存之后:
- 重复请求不会打到 R2
- 响应速度更快
1 | export default { |
其他方案
看到有人用 D1 数据库做访问次数限制 使用 Cloudflare Worker 的免费账户限制 R2 的支出(新版本更新使用 D1 数据库限制次数) ,适合更精细的控制。但我觉得对于普通用途,Worker 的每日 10 万次限制 + 缓存已经够用了
进一步优化缓存 (20250805)
- 设置响应头
1
headers.set('Cache-Control', 'public, max-age=2592000');
- 缓存键根据 URL
1
2const cacheKey = new Request(request.url, { method: "GET" });
let response = await cache.match(cacheKey); - 非 get 不响应完整版代码
1
2
3if (request.method !== 'GET') {
return new Response("Method Not Allowed", { status: 405 });
}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
44
45
46
47
48
49
50
51
52
53
54
55
56
57export default {
async fetch(request, env) {
// 仅允许 GET 请求
if (request.method !== 'GET') {
return new Response("Method Not Allowed", { status: 405 });
}
// 获取请求路径(忽略 query 参数)
const url = new URL(request.url);
const path = decodeURIComponent(url.pathname.slice(1)); // 去掉开头的 '/'
if (!path) {
return new Response("Not Found", { status: 404 });
}
// 获取默认缓存实例
const cache = caches.default;
// 使用忽略 query 参数的 URL 构建缓存 key
const cacheKeyUrl = `${url.origin}${url.pathname}`; // 不包含 search/query
const cacheKey = new Request(cacheKeyUrl, { method: "GET" });
try {
// 先尝试从缓存获取响应
let response = await cache.match(cacheKey);
if (response) {
return response; // 缓存命中,直接返回
}
// 如果缓存未命中,则从 KV 存储中获取数据
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');
// 设置缓存控制头,客户端也可缓存 1 个月
headers.set('Cache-Control', 'public, max-age=2592000'); // 1 个月缓存
// 构造响应对象
response = new Response(file.body, { headers });
// 将响应缓存以供后续请求使用
await cache.put(cacheKey, response.clone());
return response;
} catch (error) {
return new Response("Server Error", { status: 500 });
}
}
}
参考链接
- 标题: 使用 Cloudflare Workers 构建免费图床:控制 R2 成本并使用缓存
- 作者: tsvico
- 创建于 : 2025-04-09 18:20:40
- 更新于 : 2025-08-05 22:25:41
- 链接: https://blog.tbox.fun/2025/2622120444.html
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论