使用 Cloudflare Workers 构建免费图床:控制 R2 成本并使用缓存

使用 Cloudflare Workers 构建免费图床:控制 R2 成本并使用缓存

tsvico Lv5

Cloudflare R2 确实是个好东西,10GB 免费空间加上每月一千万次免费 Class B 操作,比某 AWS 不知道高到哪里去了。但是有个坑:公开存储桶的请求次数是不设防的。万一有人恶意刷你的桶,或者你的资源突然火了被疯狂访问,账单能直接让你破产。

如何用 Cloudflare Worker 给 R2 图床加个安全阀

解决方案

其实原理很简单:用 Worker 当中间人。把存储桶设为私有,然后通过 Worker 来代理访问。这样有两个好处:

  1. Worker 免费版每天 10 万次请求限制成了天然防火墙
  2. 还能顺手加个缓存,减少实际访问 R2 的次数

具体操作

第一步:创建 R2 存储桶

  1. 进 Cloudflare 控制台
  2. 找到 R2 页面
  3. 点” 创建存储桶”
  4. 起个名字(比如 my-private-bucket
  5. 重要:别勾选” 公开访问”

第二步:创建 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 });
}
}
}

第三步:绑定资源

  1. 在 Worker 设置里找到” 资源绑定”
  2. 添加新绑定:
    • 变量名:OPCT(随便起,但代码里要用一样的)
    • 类型:R2 存储桶
    • 选择你刚创建的存储桶

注意事项

  1. Worker 位置:保持默认就行,选” 智能路由” 反而可能把请求都路由到存储桶所在区域

为什么需要缓存

最开始我用的无缓存版本,在讨论帖我使用 CloudflareWorker 做地球图片后端,我试图使用 Cloudflare 缓存但 cf-cache-status 字段缺失没有缓存中发现我的图床也一样,响应头里没有 cf-cache-status,说明完全没走缓存。查了文档才知道要用 caches.default 这个 API。加了缓存之后:

  1. 重复请求不会打到 R2
  2. 响应速度更快
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 });
}

// Get cache instance
const cache = caches.default;

try {
// First try to get from cache
let response = await cache.match(request);

if (response) {
return response; // Return cached response if found
}

// If not in cache, get from OPCT
const file = await env.OPCT.get(path);

if (!file) {
return new Response("Not Found", { status: 404 });
}

// Create response with proper headers
const headers = new Headers();
headers.set('Content-Type', file.httpMetadata?.contentType || 'application/octet-stream');
// Set cache control headers (adjust TTL as needed)
headers.set('Cache-Control', 'public, max-age=3600'); // 1 hour cache [^1]

response = new Response(file.body, { headers });

// Store in cache for future requests
await cache.put(request, response.clone()); // [^2]

return response;
} catch (error) {
return new Response("Server Error", { status: 500 });
}
}
}

其他方案

看到有人用 D1 数据库做访问次数限制 使用 Cloudflare Worker 的免费账户限制 R2 的支出(新版本更新使用 D1 数据库限制次数) ,适合更精细的控制。但我觉得对于普通用途,Worker 的每日 10 万次限制 + 缓存已经够用了

参考链接

  1. 使用 Cloudflare Worker 的免费账户限制 R2 的支出(新版本更新使用 D1 数据库限制次数)
  2. 我使用 CloudflareWorker 做地球图片后端,我试图使用 Cloudflare 缓存但 cf-cache-status 字段缺失没有缓存
  3. 使用 Cloudflare Workers 中的 Cache API 来全局缓存,减少 KV 的读写,可跨 worker 缓存
  • 标题: 使用 Cloudflare Workers 构建免费图床:控制 R2 成本并使用缓存
  • 作者: tsvico
  • 创建于 : 2025-04-09 18:20:40
  • 更新于 : 2025-04-15 10:15:21
  • 链接: https://blog.tbox.fun/2025/2622120444.html
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论