跳到主要内容

《林一的 Cloudflare 通关记》第 3 篇-给网站请个"超级快递员"——CDN加速与缓存策略

· 阅读需 19 分钟

《林一的 Cloudflare 通关记》第3篇

周一早上,林一刚端着咖啡坐下,企业微信就弹出来一条消息。

产品经理小王:「林一,星火AI的页面我刚才在手机上试了一下,加载了整整8秒。我在朋友圈看到人家说,网页加载超过3秒,53%的用户就会离开。咱们这个……是不是有点太慢了?」

故事:网站上线了,但用户等得花都谢了

林一心里咯噔一下,赶紧打开浏览器测试。果然,首屏加载时间7.8秒,光等那个最大的JS文件就花了4秒多。他下意识看了眼老张的工位——老张正悠哉地喝着茶,好像早就知道这件事会发生。

「张哥,网站太慢了,小王又来催了……」

老张放下茶杯,笑了:「意料之中。你想啊,你的源服务器在上海,一个广州的用户访问你的网站,请求要跨越大半个中国。一个JS文件2MB,一个CSS文件800KB,加上几张图片,用户每次访问都得等这些文件从上海一路跑到广州。你说慢不慢?」

「那怎么办?把服务器搬到广州去?」

「搬一个地方有什么用?北京的用户怎么办?成都的用户怎么办?」老张摇了摇头,「你需要的是一个超级快递员——它在全国各地都有前置仓库,提前把你的网页内容存好。用户一访问,直接从最近的仓库取货,根本不用跑到上海去。」

「您说的是……CDN?」

「没错。今天就来给你的网站请一个Cloudflare的超级快递员。」


技术讲解:CDN到底是怎么加速的

一、CDN的核心原理:从"快递"说起

老张在白板上画了一张图。

「假设你的源服务器是一家位于上海的工厂,生产各种商品(网页文件)。用户是遍布全国的顾客。」

没有CDN的世界:

每个顾客下单后,商品都从上海工厂直接发货。广州的顾客要等3天,北京的顾客要等4天,新疆的顾客可能要等一周。工厂门口排起了长队,快递车进进出出,忙得不可开交。

有CDN的世界:

你在全国各地的快递站(边缘节点)都建了前置仓库。工厂提前把热门商品送到各个仓库里。广州的顾客下单,直接从广州仓库发货,当天到。北京的顾客从北京仓库发货,也是当天到。工厂门口再也不会排长队了。

老张在白板上写下几个关键词:

用户请求 → 边缘节点(就近) → 缓存命中?
├── 命中(HIT)→ 直接返回内容
└── 未命中(MISS)→ 回源获取 → 缓存一份 → 返回内容

这就是CDN的核心流程:

CDN核心流程:用户请求经过边缘节点,HIT直接返回,MISS回源后缓存再返回

  1. 用户发起请求:用户在浏览器输入 spark-ai.com
  2. DNS解析到最近节点:Cloudflare的Anycast网络将用户引导到地理上最近的边缘节点(比如广州用户连到广州节点)
  3. 缓存判断:边缘节点检查自己的缓存里有没有这个资源
  4. 缓存命中(Cache HIT):直接把缓存的内容返回给用户,毫秒级响应
  5. 缓存未命中(Cache MISS):边缘节点向源服务器发起回源请求(Origin Pull),拿到内容后存一份在缓存里,再返回给用户

「这里有个关键概念叫缓存命中率,」老张强调,「就是有多少比例的请求能直接从边缘节点拿到缓存,不用回源。命中率越高,用户越快,源服务器越轻松。一个配置良好的CDN,命中率能到90%以上。」

林一若有所思:「那第一次访问的内容肯定都是MISS吧?」

「对,第一次访问必须回源。但之后同一个边缘节点的其他用户再访问同样的内容,就能直接命中缓存了。这就叫请求合并(Request Collapsing)——多个用户同时请求同一个未缓存资源时,Cloudflare只向源站发一次请求,其他人等着分享结果就行。」

二、Cloudflare的全球快递网络

「Cloudflare的快递网络有多大?」林一好奇地问。

老张翻出Cloudflare的官方数据:「Cloudflare的Anycast网络覆盖了全球330多个城市。这跟阿里云CDN、腾讯云CDN的思路一样——都是在全国各地部署节点,让用户就近访问。区别在于Cloudflare的Anycast路由技术比较特殊:所有的边缘节点共享同一组IP地址,用户的请求会自动被路由到网络距离最近的节点,不需要DNS智能调度那一层。」

Anycast小科普:传统的单播(Unicast)是一个IP对应一台服务器;Anycast是一个IP对应多台服务器,网络路由协议会自动把请求送到最近的那台。就像119报警电话,你在北京打就接北京消防,在上海打就接上海消防,号码一样但接的人不一样。

「Cloudflare在全球有330多个城市的节点,这意味着绝大多数用户都能在50毫秒内连到一个边缘节点。你的源服务器在上海?没关系,美国的用户连的是美国节点,欧洲的用户连的是欧洲节点,根本不用跨洋找你。」

Cloudflare全球330+城市Anycast网络,用户就近连接边缘节点

三、什么该缓存,什么不该缓存

「好了,现在关键问题来了,」老张敲了敲桌子,「不是所有东西都该放进快递仓库的。你想想,如果你缓存了用户的实时聊天消息,那广州用户看到的就是5分钟前的旧消息——这还得了?」

该缓存的(静态资源):

资源类型举例建议缓存时间
CSS/JS文件app.css, bundle.js1天~30天
图片logo.png, banner.jpg7天~30天
字体文件roboto.woff230天~1年
视频/音频教程视频MP47天~30天
静态HTML关于我们、帮助文档1小时~1天

该缓存(CSS/JS/图片/字体/视频)vs 不该缓存(API/实时数据/管理后台/表单)的资源类型对比

不该缓存的(动态资源):

资源类型举例原因
API响应/api/user/profile每个用户数据不同
实时数据/api/chat/messages需要最新数据
管理后台/admin/dashboard权限敏感
表单提交POST请求不可缓存

「Cloudflare默认只会缓存特定扩展名的静态文件,」老张打开了Cloudflare的文档页面,「比如 .css.js.png.jpg.gif.svg.woff2.mp4.pdf 等等。注意,HTML和JSON默认不会被缓存——这是个好设计,防止你不小心缓存了动态页面。」

「那如果我的HTML页面是纯静态的呢?比如用Vue/React打包出来的单页应用?」

「那就需要用Cache Rules来手动配置了。这也是今天的重头戏。」

四、Cache Rules:你的缓存指挥棒

老张在白板上画了一个示意图:

Cache Rules = 匹配条件 + 缓存行为

├── 匹配什么? → URL / 路径 / 文件扩展名 / 主机名 / User-Agent ...

└── 怎么缓存? → 缓存 / 不缓存 / Edge TTL / Browser TTL / Cache Key ...

Cache Rules的四个核心配置项:Cache Eligibility / Edge TTL / Browser TTL / Cache Key

「Cache Rules是Cloudflare现在主推的缓存配置方式。它的逻辑很简单:当请求满足某个条件时,就执行某个缓存动作。」

四个核心配置项:

1. Cache Eligibility(缓存资格)

最基础的选择:

  • Eligible for cache:让Cloudflare尝试缓存匹配的请求
  • Bypass cache:匹配的请求不走缓存

「比如你想让 /api/* 路径下的所有请求都不缓存,就写一条规则:当路径以 /api/ 开头时 → Bypass cache。」

2. Edge TTL(边缘缓存时间)

「这是内容在Cloudflare边缘节点上缓存多久的设置。注意,这个值对用户不可见——它只影响Cloudflare自己的缓存。」

Edge TTL有三种模式:

模式含义适用场景
遵循源站Cache-Control头,没有就跳过缓存Cache-Control头就按它来,没有就不缓存源站缓存头配置完善时
遵循源站Cache-Control头,没有就用默认行为Cache-Control头就按它来,没有按Cloudflare默认规则源站配置不完善时的兜底
忽略源站头,强制使用此TTL不管源站说什么,都按这里设置的来需要完全覆盖源站行为

「Free套餐的Edge TTL最短2小时,Pro是1小时。也就是说你在Free套餐里设Edge TTL,最小只能设7200秒。」

补充知识:当源站没有发送 Cache-ControlExpires 头时,Cloudflare会按状态码给默认TTL:

  • 200/206/301 → 120分钟
  • 302/303 → 20分钟
  • 404/410 → 3分钟
  • 其他状态码 → 不缓存

「这里有个新手容易踩的坑,」老张特意加重了语气,「Cloudflare默认会尊重源站的Cache-Control。如果你的源站返回了 Cache-Control: no-cache,那不管你在Cache Rules里怎么设Edge TTL,Cloudflare都不会缓存。要覆盖这个行为,你得选第三种模式——'Ignore cache-control header and use this TTL'。」

林一赶紧记下来:「难怪我之前配了缓存规则但没生效……原来是源站的头在捣鬼。」

3. Browser TTL(浏览器缓存时间)

「这个跟Edge TTL是两回事,新手特别容易搞混。」

老张画了一张对比图:

                    Edge TTL              Browser TTL
缓存位置: Cloudflare边缘节点 用户浏览器
影响谁: Cloudflare是否会缓存 浏览器是否会缓存
对用户可见: 不可见(响应头里看不到) 可见(通过Cache-Control头)
清除方式: Purge Cache可以清除 Purge管不了浏览器缓存!

「Edge TTL管的是Cloudflare仓库里的存货能放多久;Browser TTL管的是用户浏览器里的存货能放多久。两者独立设置,互不影响。」

Edge TTL(Cloudflare边缘节点/不可见/Purge可清除)vs Browser TTL(用户浏览器/可见/Purge管不了)

Browser TTL也有三种模式:

  • Respect origin:遵循源站的缓存头
  • Override origin:覆盖源站,使用自定义值
  • Bypass:浏览器绕过缓存

「有个关键点要注意:清除Cloudflare缓存不会影响用户浏览器里的缓存。你把Cloudflare上的旧文件清了,但用户浏览器里还存着旧版本,直到Browser TTL到期。这就是为什么静态资源的文件名最好带上hash——比如 app.a3f2b1.js——文件一改,名字就变,浏览器自然去请求新的。」

4. Cache Key(缓存键)

「缓存键决定了Cloudflare怎么区分不同的缓存条目。默认情况下,缓存键就是URL(不含查询参数)。但有时候你需要更精细的控制。」

常见的Cache Key设置:

  • 忽略查询参数顺序?a=1&b=2?b=2&a=1 当作同一个缓存
  • 按设备类型缓存:桌面端和移动端返回不同页面时使用
  • 按查询参数缓存:决定哪些参数影响缓存内容

五、Page Rules:即将退休的老前辈

「你在Cloudflare的Rules菜单里可能还会看到Page Rules,」老张说,「这是Cloudflare早期的缓存配置方式,功能类似Cache Rules,但更简单也更粗糙。」

「Cloudflare官方已经明确表示,Page Rules正在逐步被Cache Rules取代。新功能只在Cache Rules里添加,Page Rules不会再更新了。所以如果你是刚开始配置,直接用Cache Rules就行,不用管Page Rules。」

「Free套餐Cache Rules可以创建10条规则,Pro是25条,对企业级应用也够用了。」

六、开发模式(Development Mode):调试好帮手

「还有一个实用功能叫Development Mode,」老张说,「开启后,Cloudflare会临时绕过所有缓存,所有请求直接回源。这样你修改了源站内容后,能立刻看到效果,不用先Purge Cache。」

「Development Mode默认持续3小时,到期后自动关闭。适合你在开发调试时临时使用。注意:它只影响Edge缓存,不影响浏览器缓存。所以调试时最好配合浏览器的无痕模式使用。」


实操:给星火AI配置缓存策略

「理论讲完了,动手吧。」老张拍了拍林一的肩膀。

步骤一:查看当前缓存情况

「先看看你网站现在的加载情况。」

林一打开Chrome DevTools,切到Network面板,刷新页面:

app.bundle.js    2.3MB    4.2s    (MISS)
style.css 890KB 2.1s (MISS)
logo.png 120KB 0.8s (MISS)
index.html 4KB 0.3s (DYNAMIC)

「全都是MISS,说明第一次加载什么都没缓存。而且你看HTML的状态是DYNAMIC——Cloudflare没缓存它,这是正确的默认行为。但JS和CSS文件虽然Cloudflare默认会缓存,第一次访问还是要回源。我们来看看第二次访问的效果。」

林一再次刷新:

app.bundle.js    2.3MB    45ms   (HIT)
style.css 890KB 32ms (HIT)
logo.png 120KB 18ms (HIT)
index.html 4KB 280ms (DYNAMIC)

缓存命中效果对比:第一次MISS 7.8秒 vs 第二次HIT 45毫秒,缓存命中率94%

「看!从4.2秒降到了45毫秒,这就是CDN缓存命中的威力。」

步骤二:创建Cache Rules

「现在来配几条缓存规则,让缓存策略更精细。」

规则1:静态资源长期缓存

登录Cloudflare Dashboard → 选择域名 spark-ai.com → 左侧菜单 CachingCache RulesCreate rule

规则名称:静态资源长期缓存

匹配条件:
When incoming requests match → Custom filter expression
Field: URI Path Extension
Operator: is in
Value: css, js, png, jpg, jpeg, gif, svg, woff2, ico, webp

缓存行为:
Cache eligibility → Eligible for cache
Edge TTL → Ignore cache-control header and use this TTL → 7 days
Browser TTL → Override origin → 7 days

点击 Deploy

老张解释:「CSS、JS、图片这些静态资源改了就换文件名(带hash),所以可以放心设长一点的缓存时间。7天是个稳妥的选择。」

规则2:API接口不缓存

规则名称:API接口绕过缓存

匹配条件:
When incoming requests match → Custom filter expression
Field: URI Path
Operator: starts with
Value: /api/

缓存行为:
Cache eligibility → Bypass cache

点击 Deploy

「API接口必须实时返回最新数据,绝对不能缓存。」

规则3:首页HTML缓存1小时

规则名称:首页HTML短期缓存

匹配条件:
When incoming requests match → Custom filter expression
Field: URI Path
Operator: equals
Value: /

缓存行为:
Cache eligibility → Eligible for cache
Edge TTL → Use cache-control header if present, use default Cloudflare caching behavior if not
Browser TTL → Respect origin

点击 Deploy

「首页内容偶尔更新,缓存1小时够了。这里Edge TTL选遵循源站,如果你的源站配了 Cache-Control: public, max-age=3600 就会按1小时来。没配的话,Cloudflare会按默认行为处理。」

步骤三:验证缓存规则是否生效

「配置完了不等于配对了,得验证。」老张打开了Cloudflare的Trace工具。

在浏览器访问 https://spark-ai.com/cdn-cgi/trace,可以看到当前请求被路由到了哪个节点:

fl=xxxxx
h=spark-ai.com
ip=xxx.xxx.xxx.xxx
visit_scheme=https
colo=HKG ← 香港节点
...

colo字段显示你连的是哪个边缘节点。我在深圳,连到了香港节点(HKG),延迟很低。」

更详细的验证可以用浏览器开发者工具查看响应头:

CF-Cache-Status: HIT        ← 缓存命中
CF-Cache-Status: MISS ← 缓存未命中,已回源
CF-Cache-Status: DYNAMIC ← 未被缓存(默认不缓存的类型)
CF-Cache-Status: BYPASS ← 被规则跳过缓存
CF-Cache-Status: EXPIRED ← 缓存已过期,正在回源

林一测试后发现CSS和JS都返回 HIT,API接口返回 BYPASS,首页HTML返回 HIT。一切正常。

步骤四:更新内容后清除缓存

「假设你修改了CSS文件并部署到了源站,但Edge TTL还没到期,用户看到的还是旧版本。这时候怎么办?」

「去Cloudflare后台点Purge?」

「对,Cloudflare支持几种清除方式:

  • Purge Everything:一键清除所有缓存。简单粗暴,但会导致短期内大量回源请求。
  • Purge by URL:只清除指定URL的缓存(推荐)。
  • Purge by Prefix:按路径前缀清除,比如 /assets/*
  • Purge by Hostname:按域名清除。
  • Purge by Cache-Tag:按标签清除(需要先在响应头里设置Cache-Tag)。」

「Free套餐也支持按URL清除,每秒最多清除800个URL。如果只是改了一个CSS文件,Purge那一个URL就行,其他缓存不受影响。」

老张演示了在Dashboard里操作:CachingConfigurationPurge CacheCustom Purge → 输入URL → Purge

「如果你用了带hash的文件名方案,其实连Purge都不用——文件名一变,URL就变了,Cloudflare自然当成新资源去回源。旧的缓存等TTL到期后自动失效。」

步骤五:开启Development Mode调试

「如果需要频繁修改源站内容并实时查看效果,」老张说,「可以临时开启Development Mode。」

CachingConfiguration → 找到 Development Mode → 切换为 On

「开启后3小时内,所有请求直接回源,不走缓存。调试完记得手动关掉,不然你的缓存命中率就归零了。」


小结

老张看了看时间,今天的讲解差不多该收尾了。

「总结一下今天做的事:CDN的本质就是把内容提前放到离用户最近的地方,让用户不用每次都跑到源服务器去取。Cloudflare的全球网络覆盖330多个城市,用户几乎都能就近连到一个节点。」

「配置上记住三个层次:什么该缓存(Cache Eligibility)、缓存多久(Edge TTL + Browser TTL)、缓存怎么区分(Cache Key)。Cache Rules是你配这些的主要工具,正在取代老旧的Page Rules。」

「还有个铁律:清除Cloudflare缓存管不了用户浏览器里的缓存。所以静态资源一定要用带hash的文件名,这样改了内容文件名就变,浏览器自然会请求新的。」

林一点点头,在笔记本上写下了今天的成果——首屏加载时间从7.8秒降到了1.2秒,缓存命中率达到94%。

本篇知识点回顾

知识点要点
CDN工作原理用户→边缘节点→缓存命中直接返回/未命中则回源→缓存→返回
缓存命中率HIT次数占总请求的比例,目标90%以上
Cloudflare全球网络330+城市Anycast网络,用户自动路由到最近节点
默认缓存行为按文件扩展名缓存(css/js/png等),HTML/JSON默认不缓存
Cache Rules匹配条件+缓存行为,Free套餐10条规则
Edge TTLCloudflare边缘节点的缓存时间,Free最小2小时
Browser TTL用户浏览器的缓存时间,默认4小时,Purge管不了它
Cache Key缓存条目的唯一标识,可按设备/查询参数等定制
Page Rules正在被Cache Rules取代,不建议新建
Development Mode临时绕过缓存3小时,调试用
Purge Cache按URL清除(推荐)/全部清除/按前缀清除等
静态资源命名带hash文件名(如app.a3f2b1.js),改了名就自动刷新

动手挑战

  1. 基础题:给你的域名创建一条Cache Rule,让所有图片文件(png/jpg/gif/svg/webp)缓存30天,Browser TTL也设30天。
  2. 进阶题:用 /cdn-cgi/trace 接口查看你连的是哪个边缘节点,然后用DevTools的Network面板查看 CF-Cache-Status 响应头,确认缓存是否命中。
  3. 思考题:如果你有一个 /api/products 接口返回商品列表,数据每小时更新一次,你会怎么配置缓存策略?(提示:考虑API缓存的安全边界和时效性)

下回预告

速度搞定了,缓存命中率94%,林一正准备向小王邀功,老张却问了一句:「你的前端代码现在部署在哪?」

「呃……本地跑的,用ngrok映射出去的……」

老张叹了口气:「前端代码还躺在本地电脑上,电脑一关网站就没了。该给网站安个家了。明天教你用Cloudflare Pages,把前端代码直接部署到Cloudflare的全球网络上——不用服务器、不用配置nginx、一条命令上线。」

林一眼睛一亮:「还有这种好事?」

「免费套餐够你用了。明天见。」


本文是《林一的 Cloudflare 通关记》系列第3篇。 上一篇:加密通道——SSL/TLS配置与Origin CA证书 下一篇:给网站安个家——Cloudflare Pages部署前端

wp