Cloudflare Workers 全栈应用:正确使用 Cache API 加速网站
摘要
在 Cloudflare Workers 上,仅设置 Cache-Control 响应头无法阻止请求进入 Worker。本文介绍如何使用 Cache API 在全球边缘节点缓存 HTML 响应以跳过 SSR 渲染,并配合 Purge API 实现精准的编程式缓存失效。
💡 写在前面:这篇文章介绍的是 Cloudflare 经典的 Cache API 方案。它能在边缘持久化 HTML 响应并跳过耗时的 SSR 渲染,但请求依然会触发 Worker 的
fetch入口,产生基础的 CPU 运行时长。如果你追求更极致的「缓存命中时完全不启动 Worker、CPU 计费归零」,可以参考后续的新特性实践:《从 Cache API 到 Workers Cache:命中不再消耗 CPU Time》。下面我们仍聚焦于 Cache API 自身的工作原理与实践细节。
在使用 Cloudflare Workers 构建全栈 Web 应用时,很多开发者容易陷入一个误区:以为只要在 Worker 的 Response 中设置了标准的 HTTP 缓存头(如 Cache-Control: public, max-age=3600),Cloudflare 的 CDN 就会自动把 Worker 挡在身后。
但在 Workers 的请求执行流程中,事实恰好相反。
默认情况下,一旦请求匹配到 Worker 路由,流量会直接穿透进 Worker 实例。Worker 返回带有 Cache-Control 的响应,并不代表 Cloudflare 的边缘节点会自动为你留存一份静态拷贝。在控制台观察响应头时,cf-cache-status 经常是 DYNAMIC。这意味着每一个请求都在完整执行 SSR 渲染和数据库查询,白白消耗大量宝贵的 CPU Time。
要在边缘节点把渲染好的 HTML 存下来、让后续请求跳过 SSR,必须在 Worker 内部显式使用 Cache API。需要注意:在此模式下,请求依然会进入 Worker 的 fetch 入口去执行 cache.match——省下的是渲染计算,而不是这次请求调用本身。
1. 正确做法:使用 Cache API 接管边缘缓存
我们需要在 Worker 内部手动拦截请求:先在 caches.default 中查询是否存在现成缓存;命中则直接返回;未命中时才执行业务逻辑或渲染流程,并将结果写回缓存。
以下是一个标准的 TypeScript 实现模板:
在上面的实现中,有两个关键细节值得注意:
`response.clone()`:Response 对象的 Body 本质上是单向流(ReadableStream),一旦被读取或传送给客户端就无法再次使用。因此在存入缓存时必须使用
clone()拷贝一份。`ctx.waitUntil`:将
cache.put的 Promise 托付给执行上下文。这样 Worker 可以立刻向客户端返回渲染好的页面,写入缓存的过程在后台异步完成,既不会拖慢响应速度,也不会因为请求结束而被平台过早销毁。
2. 进阶策略:长 TTL 搭配主动 Purge API
当你能够精确掌控缓存生命周期时,就可以采用更激进的加速策略:把 s-maxage 设置得更长(例如一天甚至一周),平时让边缘缓存承担几乎全部流量;当内容更新时,再通过编程式刷新(Purge)来保证数据的实时性。
Cloudflare 官方提供了灵活的 Purge API,支持按精确 URL或前缀(Prefix)清除边缘缓存。你只需要在 Cloudflare 控制台创建一个拥有 Zone.Cache:Purge 权限的 API Token 即可:
借助这套机制,博客或文档类站点在发布新内容、编辑文章或收到新评论时,只需触发对应的 Purge 调用,就能实现「平时极速静态分发,修改时秒级全网同步」。
3. 总结与演进
Cache API 是在 Cloudflare Workers 上实现边缘加速最经典的工具,仅需十几行代码就能大幅卸载数据库与计算压力。
不过从底层架构来看,无论缓存是否命中,请求都会先经历一次 Worker 实例的调度与唤醒。如果你正在构建新的全栈应用,并且希望在缓存命中时完全不启动任何 Worker 实例、让 CPU Time 彻底归零,可以进一步阅读下一阶段的演进方案:《从 Cache API 到 Workers Cache:命中不再消耗 CPU Time》。
