Workers免费额度不够用?7个优化技巧让10万次撑一个月

引言
上个月我用 Workers 搭了个图床,结合 R2 存储,感觉挺完美。结果没到3天,就收到 Cloudflare 的邮件:你的免费额度快用完了。 我一脸懵:不是说每天10万次吗?我这小破图床能有多少流量?点开 Analytics 一看,日均12万次请求。这怎么可能?我明明才上传了几十张图片。 后来花了两天研究文档、翻社区讨论,才搞明白 Workers 的计费有多少坑。什么子请求、KV读取、缓存命中,每个都在”偷偷”消耗你的额度。 不过好消息是,搞清楚规则后,我用了几个优化技巧,把日请求量从12万降到3万。现在每月免费额度不仅够用,还能剩30%。今天就把这些实战经验分享给你,希望能帮你省下每月5美元的付费计划费用。
别被骗了!Workers的”10万次”不是你想的那样
说实话,Cloudflare 文档上写的”10万次请求/天”,很容易让人误解。我刚开始以为是:我的 Worker 被访问10万次就到顶了。其实不是这么算的。 真相1:子请求不单独计费,但有数量限制 Worker 里用 fetch() 去调用其他 API、读取 R2、查询 KV,这些都叫子请求。好消息是:子请求不单独算钱。坏消息是:免费计划每个请求只能发50个子请求,付费才能到1000个。 打个比方:用户访问你的图床网址(1次计费请求),Worker 里要查 KV 验证权限(1个子请求),再从 R2 拉图片(1个子请求)。虽然有2个子请求,但只算1次计费。 如果你做个聚合服务,一次请求要调10个 API,那就是10个子请求。免费计划50个的限制,听起来挺多,实际项目里很容易碰到天花板。 真相2:10万是账号级别限制,不是单个 Worker 这点挺坑的。我一开始以为可以搞多个 Worker 分散流量,后来发现10万次是整个账号的限制。你注册10个 Worker,加起来还是只有10万次。 想靠多 Worker 规避限额?不行的。社区里有人试过,Cloudflare 的限制是按账号来的。要突破只能付费,或者优化请求次数。 真相3:KV读写、Cache API操作都算请求 这个最容易被忽略。Worker 每次 KV.get() 读取数据,虽然不算子请求限制,但会消耗请求次数。如果你的 Worker 每次都要读 KV 验证权限,那等于每个用户访问都要多消耗1次 KV 操作。 Cache API 也一样。虽然用 Cache 能减少对源站的请求,但 Cache 的 match() 和 put() 操作本身也有成本。 最容易踩的3个坑 我当时就是踩了这几个坑,才导致请求次数爆炸:
- 坑1:反向代理每次都发子请求,没用缓存 我做了个 API 中转服务,每次都
fetch()原始 API。没想到缓存,结果每个用户请求都要发子请求。后来加了 Cache API,命中率80%,请求次数直接砍一半。 - 坑2:KV读取频繁,不知道 cacheTtl 参数 图床项目里,每张图片都要
KV.get()查权限。我不知道可以设cacheTtl参数,让 KV 在边缘节点缓存数据。改成cacheTtl: 600(10分钟)后,KV 读取减少了70%。 - 坑3:重定向链每个跳转都计数 我之前做短链服务,用 Worker 返回
302重定向。后来发现,如果重定向链有3次跳转(A→B→C→目标),每次跳转都算1个子请求。改成直接返回最终地址,省了2次计数。 这些坑加起来,就是我从10万超到12万的原因。如果你也遇到额度不够用,先自查是不是踩了这些坑。
7个优化技巧,让免费额度多撑一个月
搞清楚计费规则后,我试了很多优化方案。这7个技巧是经过实战验证的,效果最明显、实现也不复杂。 技巧1:用好缓存,减少80%的重复请求 这是我试下来见效最快的方法。很多 Worker 项目其实不需要每次都实时计算,完全可以缓存结果。 我的图床项目优化前,每次访问图片都要走一遍完整流程:验证→读 R2→返回。优化后加了 Cache API:
const cache = caches.default;
const cacheKey = new Request(request.url, request);
// 先查缓存
let response = await cache.match(cacheKey);
if (response) {
return response; // 缓存命中,直接返回
}
// 缓存未命中,处理请求
response = await handleRequest(request);
// 设置缓存(静态图片缓存1天)
response = new Response(response.body, {
...response,
headers: {
...response.headers,
'Cache-Control': 'public, max-age=86400',
},
});
await cache.put(cacheKey, response.clone());
return response;改完后,缓存命中率85%。原来日均12万次请求,现在只有1.8万次真正走 Worker 逻辑,省了10.2万次。 技巧2:KV优化三板斧 KV 是 Workers 里最常用的存储,但也是请求次数的大头。我总结了3个优化点:
- 增加 cacheTtl 参数 KV 默认在边缘节点缓存60秒。如果你的数据更新不频繁,可以加大这个值:
我的权限验证数据半小时才更新一次,设成// 优化前 const value = await KV.get('key'); // 优化后(缓存10分钟) const value = await KV.get('key', { cacheTtl: 600 });cacheTtl: 1800,KV 读取直接减少70%。 - 用 Cache API 缓存 KV 结果 如果数据更新更慢(比如配置文件、黑名单),可以在 Worker 层再加一层缓存:
const cacheKey = `kv-cache:${key}`; let cached = await caches.default.match(cacheKey); if (!cached) { const value = await KV.get(key); cached = new Response(value); await caches.default.put(cacheKey, cached.clone()); } return cached.text(); - 用 waitUntil 做非阻塞写入 如果要写 KV 但不需要等结果,用
waitUntil可以不阻塞响应:// 不等 KV 写入完成就返回响应 event.waitUntil(KV.put('key', 'value')); return new Response('OK');
这三招组合,让我的 KV 操作从日均3万次降到8000次。 技巧3:减少不必要的子请求 很多时候,子请求是可以优化掉的。 我之前做个聚合服务,要调5个外部 API,然后合并结果返回。每次请求 = 5个子请求。后来我改成:
- 高频 API 的结果缓存5分钟
- 低频 API 的结果用 KV 存24小时
- 如果可以,直接把数据预处理好存 R2 优化后,80%的请求不需要发任何子请求,直接从缓存返回。 技巧4:善用 Request.cache 控制缓存行为 Cloudflare 在2024年11月新增了
Request.cache属性,可以更精细地控制缓存:
// 跳过缓存(适合敏感数据)
const response = await fetch(url, { cache: 'no-store' });
// 使用默认缓存策略
const response = await fetch(url, { cache: 'default' });我在处理用户私密图片时,用 cache: 'no-store' 确保不会被 CDN 缓存。公开图片用 default,让 Cloudflare 自动优化。 技巧5:优化重定向链 如果你的 Worker 会返回重定向(302/301),注意重定向链中的每次跳转都算子请求。 我的短链服务优化前:
// 优化前:返回302重定向
return Response.redirect(targetUrl, 302);优化后:
// 优化后:缓存目标地址,减少重定向
const cached = await cache.match(shortUrl);
if (cached) {
return cached; // 直接返回缓存的最终地址
}对于会多次跳转的链接(比如 bit.ly → t.co → 最终网址),直接存储最终地址,避免每次都走重定向链。 技巧6:监控请求分布,找出”吞金兽” Cloudflare 的 Analytics 是免费的,一定要用起来。 我发现一个规律:80%的请求量往往来自20%的路径。在 Workers Analytics 里,可以看到:
- 哪些路径请求最多
- 哪些路径缓存命中率低
- 哪些路径耗时最长 找出请求量最大的几个路径,针对性优化。我当时发现
/api/status这个健康检查接口,被监控服务每分钟调100次,占了日请求量的15%。后来给这个接口加了60秒缓存,立省1.5万次/天。 技巧7:分时段处理非紧急任务 Workers 支持 Cron Triggers,可以定时执行任务。如果有些任务不是实时的(比如统计、清理、预热缓存),可以放到低峰期。 我的图床有个功能:每小时统计访问量。之前是每次访问都写 KV 计数器,后来改成: - 访问时只在内存计数(不写 KV)
- 用 Cron Trigger 每小时汇总一次 这样把频繁的 KV 写入,变成每小时1次批量操作。日均 KV 写入从2万次降到24次。
实战案例:图床项目从日均12万→3万次
前面讲了这么多技巧,你可能会想:组合起来效果到底怎么样?我就拿自己的图床项目举例,完整复盘一遍优化过程。 项目背景 这是个简单的图床服务,技术栈:
- Cloudflare Workers 处理请求
- R2 存储图片文件
- KV 存储图片元数据和权限
- 日均约2000张图片访问(真实用户流量) 上线第3天,收到 Cloudflare 提醒:日均12万次请求,接近免费额度上限。 问题诊断 我花了半天时间,用 Analytics 和代码审查找出了3个主要问题:
- 每次图片请求都查 KV 每张图片访问,Worker 都要
KV.get()查元数据(文件名、大小、上传者)。2000张图片访问 = 2000次 KV 读取。但这些元数据基本不变,根本不需要每次都查。 - 没有浏览器缓存 我的响应头里没设
Cache-Control,导致用户刷新页面,浏览器都要重新请求。同一张图片被同一个用户请求10次,Worker 就被调用10次。 - 缩略图实时生成 图片列表页显示缩略图,我用 Worker 实时裁剪生成。一个列表页30张图 = 30次图片处理请求。用户翻几页,请求次数就爆了。 这三个问题,导致实际2000次有效访问,变成12万次 Worker 调用。 优化方案 针对这3个问题,我按优先级做了优化: 第1步:KV 缓存优化(见效最快) 给 KV 读取加
cacheTtl参数:
// 优化前
const metadata = await IMAGE_KV.get(imageId);
// 优化后
const metadata = await IMAGE_KV.get(imageId, {
cacheTtl: 600 // 缓存10分钟
});效果:KV 读取从2000次/天降到约300次/天(-85%) 第2步:添加浏览器缓存 给图片响应添加缓存头:
return new Response(imageData, {
headers: {
'Content-Type': 'image/jpeg',
'Cache-Control': 'public, max-age=86400', // 缓存1天
'CDN-Cache-Control': 'public, max-age=2592000' // CDN缓存30天
}
});效果:重复访问减少60%,请求从12万降到4.8万 第3步:缩略图预生成 不再实时生成,改为上传时预生成,存到 R2 的 thumbnails/ 目录:
// 上传时生成缩略图
const thumbnail = await generateThumbnail(image);
await R2.put(`thumbnails/${imageId}`, thumbnail);
// 访问时直接读取
const thumbnail = await R2.get(`thumbnails/${imageId}`);效果:缩略图请求不再触发 Worker 处理逻辑,请求从4.8万降到3.2万 第4步:Worker 缓存层 最后给整个响应加 Cache API:
const cache = caches.default;
let response = await cache.match(request);
if (response) return response;
// 处理请求...
await cache.put(request, response.clone());
return response;效果:缓存命中率78%,最终稳定在日均3万次左右 优化结果
| 指标 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| 日请求量 | 12万次 | 3.2万次 | -73% |
| KV 读取 | 2000次 | 300次 | -85% |
| 缓存命中率 | 0% | 78% | +78% |
| 费用 | 超额20% | 富余70% | 省60美元/年 |
| 现在这个图床稳定运行了2个月,日均请求3-4万次,免费额度完全够用。按付费计划5美元/月算,一年省下60美元。 | |||
| 经验总结 | |||
| 回头看这次优化,我总结了几个关键点: |
- 先找瓶颈,再优化:不要盲目优化,用 Analytics 找出真正的问题
- 缓存是王道:80%的优化效果来自缓存(浏览器缓存、CDN缓存、Worker缓存)
- KV 要谨慎用:能缓存的一定要设
cacheTtl,能预计算的不要实时查 - 增量优化:我是分4步优化的,每步都能看到明显效果,而不是一次改太多
付费还是优化?算笔经济账
看到这里你可能会想:我是花时间优化,还是直接付费升级?这个问题我也纠结过,后来算了笔账就清楚了。 免费计划 vs 付费计划对比
| 项目 | 免费计划 | 付费计划(5美元/月) |
|---|---|---|
| 日请求量 | 10万次 | ~33万次(1000万/月) |
| 每分钟限制 | 1000次 | 无明确限制 |
| 子请求数 | 50次/请求 | 1000次/请求 |
| KV 读取 | 10万次/天 | 1000万次/月 |
| CPU 时间 | 10ms | 50ms |
| 年费用 | 0元 | 60美元 |
| 从数据看,付费计划确实香:日请求量翻3倍,子请求限制放宽20倍。但关键是,你真的需要吗? | ||
| 什么情况该升级付费? | ||
| 我总结了3种场景,建议直接付费: |
- 日请求稳定超10万 注意是”稳定”超。如果只是偶尔流量高峰超一点,可以通过优化解决。但如果连续一周都超,说明业务量确实上来了,付费更省心。
- 需要大量子请求 如果你做爬虫、聚合服务、API网关,一次请求要调10+个外部 API,免费50次的限制肯定不够。这种情况优化空间有限,付费计划1000次的限制更合理。
- 商业项目,稳定性>成本 如果是给客户做的项目,或者自己的商业产品,别在免费额度上省这点钱。付费计划的 SLA 更有保障,出问题可以开工单。5美元换来的稳定性,远比省这点钱重要。 优化的边界在哪里? 反过来说,有些情况优化就是浪费时间:
- 过度优化导致代码复杂 为了省请求,写了一堆缓存逻辑、预计算脚本、定时任务,代码变得很难维护。这时候,你的时间成本可能远超5美元。
- 优化已经到极限 如果该加的缓存都加了,该优化的都优化了,还是不够用,那就是业务量的问题了。别硬扛,该付费付费。
- 时间成本 vs 5美元 算一下你的时薪。如果优化要花3小时,你的时薪超过20块,那直接付费更划算。 我的建议是:
- 个人项目、学习项目:优先优化,当省钱也当学习
- 小团队、初期产品:先优化到极限,再考虑付费
- 商业项目、客户项目:直接付费,别在这上面省钱 付费之后还要优化吗? 要。虽然付费计划额度高,但计费规则是一样的。如果不优化,1000万次的额度也能给你用完。 而且付费计划超额后,按每百万请求0.50美元计费。如果你日均100万次请求,一个月就是15美元超额费用,加上基础5美元 = 20美元/月。这时候优化的价值就体现出来了。
结论
说了这么多,核心就是一句话:搞清楚 Workers 怎么计费,然后用对方法优化。 Workers 的10万次免费额度,乍一看挺多,实际用起来很容易超。但大部分情况,不是业务量太大,而是没优化好。 我的图床项目就是例子:真实流量只有2000次访问,却触发了12万次请求。通过缓存、KV 优化、预计算,最终降到3万次,不仅够用还有富余。 如果你也遇到额度不够用,建议按这个步骤来:
- 打开 Workers Analytics,看看是哪些路径在”吃”额度
- 从缓存和 KV 入手,这两个优化见效最快
- 检查有没有踩本文提到的3个坑(子请求、KV cacheTtl、重定向链)
- 把前面7个技巧都试一遍,组合起来效果更好
- 如果优化到极限还不够,再考虑付费 最后提醒一句:Cloudflare 毕竟是商业公司,免费额度要合理使用。过度”薅羊毛”可能被限速,甚至封号。优化的目的是更高效利用资源,不是钻空子。 如果这篇文章帮你省下了5美元,不妨点个赞或者分享给也在用 Workers 的朋友。大家一起把免费额度用到极致。
发布于: 2025年12月1日 · 修改于: 2025年12月4日


