<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>缓存 on 寻 Mi 处</title>
        <link>https://blog.mibase.top/tags/%E7%BC%93%E5%AD%98/</link>
        <description>Recent content in 缓存 on 寻 Mi 处</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <lastBuildDate>Mon, 05 Feb 2024 02:45:00 +0800</lastBuildDate><atom:link href="https://blog.mibase.top/tags/%E7%BC%93%E5%AD%98/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>给 Cloudflare 配上缓存规则之后，博客的图片终于不用每次回源了</title>
            <link>https://blog.mibase.top/p/%E7%BB%99-cloudflare-%E9%85%8D%E4%B8%8A%E7%BC%93%E5%AD%98%E8%A7%84%E5%88%99%E4%B9%8B%E5%90%8E%E5%8D%9A%E5%AE%A2%E7%9A%84%E5%9B%BE%E7%89%87%E7%BB%88%E4%BA%8E%E4%B8%8D%E7%94%A8%E6%AF%8F%E6%AC%A1%E5%9B%9E%E6%BA%90%E4%BA%86/</link>
            <pubDate>Mon, 05 Feb 2024 02:45:00 +0800</pubDate>
            <guid>https://blog.mibase.top/p/%E7%BB%99-cloudflare-%E9%85%8D%E4%B8%8A%E7%BC%93%E5%AD%98%E8%A7%84%E5%88%99%E4%B9%8B%E5%90%8E%E5%8D%9A%E5%AE%A2%E7%9A%84%E5%9B%BE%E7%89%87%E7%BB%88%E4%BA%8E%E4%B8%8D%E7%94%A8%E6%AF%8F%E6%AC%A1%E5%9B%9E%E6%BA%90%E4%BA%86/</guid>
            <description>&lt;img src=&#34;https://blog.mibase.top/p/%E7%BB%99-cloudflare-%E9%85%8D%E4%B8%8A%E7%BC%93%E5%AD%98%E8%A7%84%E5%88%99%E4%B9%8B%E5%90%8E%E5%8D%9A%E5%AE%A2%E7%9A%84%E5%9B%BE%E7%89%87%E7%BB%88%E4%BA%8E%E4%B8%8D%E7%94%A8%E6%AF%8F%E6%AC%A1%E5%9B%9E%E6%BA%90%E4%BA%86/cover.jpg&#34; alt=&#34;Featured image of post 给 Cloudflare 配上缓存规则之后，博客的图片终于不用每次回源了&#34; /&gt;&lt;p&gt;域名托管到 Cloudflare 有一段时间了，页面打开速度一直说不上好。白天在公司摸鱼的时候打开自己的博客，首屏的图片总是一块一块地往下蹦，像是网速被谁掐了一半。&lt;/p&gt;&#xA;&lt;p&gt;打开 F12 看 Network，问题挺明显的。那些几十 KB 的封面图，每一张的响应时间都在三百毫秒往上，而且不管我刷新多少次，它都是这个速度。点开 Response Headers 一看，&lt;code&gt;CF-Cache-Status&lt;/code&gt; 是 &lt;code&gt;MISS&lt;/code&gt;，有时候干脆是 &lt;code&gt;DYNAMIC&lt;/code&gt;。意思很清楚，Cloudflare 根本没帮我存，每次都是它跑回我的 VPS 拿一遍，再转手给我。&lt;/p&gt;&#xA;&lt;p&gt;我这才认真去看了它的缓存逻辑。&lt;/p&gt;&#xA;&lt;h2 id=&#34;默认只缓存一小撮东西&#34;&gt;默认只缓存一小撮东西&#xA;&lt;/h2&gt;&lt;p&gt;Cloudflare 的免费套餐对缓存是做了限制的。它只对一部分后缀名有默认缓存行为，比如 css、js、图片、字体这些。听起来好像我需要的都在里面，但实际上还有一个坑，就是缓存时长很短，而且第一次请求之后 Edge 节点上存不存、存多久，还要看源站给的 &lt;code&gt;Cache-Control&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;我的 Nginx 那时候配置得很随便，静态资源只写了 &lt;code&gt;expires 7d&lt;/code&gt;，别的什么都没管。Cloudflare 拿到这个头，就按七天存。听着还行，可我博客的图换了之后，七天之内访客看到的还是旧图，这个体验很别扭。&lt;/p&gt;&#xA;&lt;p&gt;后来我把思路理清楚了。图片、字体、css、js 这些东西带上内容指纹，改一次文件名就变一次，这种资源可以放心地缓存很久，甚至一年。HTML 不行，HTML 一改就得让用户立刻看到新的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;换成-cache-rules&#34;&gt;换成 Cache Rules&#xA;&lt;/h2&gt;&lt;p&gt;网上很多老教程还在教你用 Page Rules。这个功能 Cloudflare 从 2023 年就开始推着大家迁走了，免费套餐能建的条数也少，表达式写法也老旧。现在应该用的是 Rules 里的 Cache Rules，逻辑更清楚，条件可以写得很细。&lt;/p&gt;&#xA;&lt;p&gt;我进控制台，左边找到 Rules，点 Cache Rules，Create rule。&lt;/p&gt;&#xA;&lt;p&gt;名字随便起，我写的是 &lt;code&gt;static-assets&lt;/code&gt;。下面 When incoming requests match 那里，选 Custom filter expression，然后填：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(http.request.uri.path.extension in {&amp;#34;jpg&amp;#34; &amp;#34;jpeg&amp;#34; &amp;#34;png&amp;#34; &amp;#34;gif&amp;#34; &amp;#34;webp&amp;#34; &amp;#34;svg&amp;#34; &amp;#34;ico&amp;#34; &amp;#34;css&amp;#34; &amp;#34;js&amp;#34; &amp;#34;woff&amp;#34; &amp;#34;woff2&amp;#34; &amp;#34;ttf&amp;#34;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这个写法比老教程里那种一串 &lt;code&gt;contains&lt;/code&gt; 拼起来要干净得多，它是直接判断路径后缀。&lt;/p&gt;&#xA;&lt;p&gt;Then 那部分做这些设置：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Cache eligibility: Eligible for cache&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Edge TTL: Ignore cache-control header and use this TTL -&amp;gt; 1 month&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Browser TTL: Override origin -&amp;gt; 1 month&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;Edge TTL 是 Cloudflare 自己节点上存多久，Browser TTL 是告诉访客的浏览器存多久。两个都拉长，命中率才上得去。免费套餐的 Edge TTL 最长就是一个月，够用了。&lt;/p&gt;&#xA;&lt;p&gt;这里有个细节值得说一下。如果你选的是 &lt;code&gt;Use cache-control header if present&lt;/code&gt;，那 Cloudflare 就会听源站的，你 Nginx 里写 7 天它就是 7 天。想让 Cloudflare 说了算，就得选 ignore 那一项。我第一次没注意，改完发现一点变化都没有，白折腾了半小时。&lt;/p&gt;&#xA;&lt;h2 id=&#34;html-也可以缓存但要小心&#34;&gt;HTML 也可以缓存，但要小心&#xA;&lt;/h2&gt;&lt;p&gt;纯静态博客有个好处，HTML 也是构建出来的静态文件，没有数据库查询，缓存起来毫无压力。我另外加了一条规则，只针对 HTML：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(http.request.uri.path.extension eq &amp;#34;&amp;#34;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;然后 Edge TTL 设成 2 小时，Browser TTL 设成 30 分钟。&lt;/p&gt;&#xA;&lt;p&gt;为什么留这么短。因为我一改文章就得让人看到新的。两小时对我来说是个能接受的窗口，写完文章去 Cloudflare 那边手动 Purge 一下就行。如果哪天忘了 Purge，最多两小时也会自己过期，不至于一直挂着旧内容。&lt;/p&gt;&#xA;&lt;p&gt;Browser TTL 我压得更短，是因为浏览器缓存最难清。用户本地存着的 HTML，你在服务器上怎么改他都不知道，只能等他缓存过期。30 分钟是个折中。&lt;/p&gt;&#xA;&lt;h2 id=&#34;源站那边也得配合&#34;&gt;源站那边也得配合&#xA;&lt;/h2&gt;&lt;p&gt;只改 Cloudflare 不管源站，效果会打折扣。我在 Nginx 里把静态资源的响应头重写了一遍：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;~&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;\.(jpg|jpeg|png|gif|webp|svg|ico|css|js|woff2?)&lt;/span&gt;$ &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;expires&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;1y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Cache-Control&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;public,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;max-age=31536000,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;immutable&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;access_log&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;off&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;immutable&lt;/code&gt; 这个值挺有用。它告诉浏览器，这个文件在有效期内绝对不会变，用户按 F5 刷新的时候不用再发一次条件请求。少了这个 &lt;code&gt;304&lt;/code&gt; 往返，刷新页面的感觉会明显快一截。&lt;/p&gt;&#xA;&lt;p&gt;前提是你的文件名得带指纹。Hugo 生成的 css 和 js 默认是带 hash 的，图片是我自己命名的，没带。所以我给图片加了个小约定，文件名后面缀上内容的前八位哈希，改图就改名，这样缓存一年也不会出问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;验证到底有没有生效&#34;&gt;验证到底有没有生效&#xA;&lt;/h2&gt;&lt;p&gt;改完之后别急着高兴，得实际去看。&lt;/p&gt;&#xA;&lt;p&gt;最直接的办法是 curl：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -sI https://blog.mibase.top/images/cover.jpg &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep -i cf-cache&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;第一次大概率是 &lt;code&gt;MISS&lt;/code&gt;，这是正常的，节点上还没有。再跑一次，应该就变成 &lt;code&gt;HIT&lt;/code&gt; 了。如果跑了好几次还是 &lt;code&gt;MISS&lt;/code&gt;，那就回去看看规则的条件是不是没匹配上，或者 Cache eligibility 是不是还停在 &lt;code&gt;Bypass cache&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;还有一个 &lt;code&gt;DYNAMIC&lt;/code&gt;，这个值的意思是 Cloudflare 认为这个请求不该走缓存。通常出现在 HTML 上，或者规则没命中。&lt;/p&gt;&#xA;&lt;p&gt;我还注意到有个 &lt;code&gt;REVALIDATED&lt;/code&gt;，那是源站返回了 304，Cloudflare 拿旧的继续用。这个状态其实也挺好，至少没重新传一遍完整内容。&lt;/p&gt;&#xA;&lt;h2 id=&#34;命中率从四成到九成&#34;&gt;命中率从四成到九成&#xA;&lt;/h2&gt;&lt;p&gt;Cloudflare 控制台的 Caching 下面有个 Analytics，能看到缓存命中率。我改之前是 41% 左右，改完第二天稳定在 92% 上下。&lt;/p&gt;&#xA;&lt;p&gt;这个数字带来的变化是很实在的。以前国内访问我的博客，图片要绕到我的 VPS 上拿，VPS 在洛杉矶，一个来回就是两百多毫秒。现在大部分请求落在 Cloudflare 离用户最近的节点上，二三十毫秒就回来了。&lt;/p&gt;&#xA;&lt;p&gt;还有一个连带的好处，源站的带宽掉得很明显。Cloudflare 后台显示回源流量少了七成多，我那台按流量计费的机器，账单也跟着降了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;几个踩过的坑&#34;&gt;几个踩过的坑&#xA;&lt;/h2&gt;&lt;p&gt;规则是有优先级的，同一个请求命中多条规则时，只有最上面那条生效。我一开始把 HTML 的规则放在最前面，结果图片规则被它盖住了，因为 HTML 那条的条件写得太宽。顺序一定要捋一遍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Purge Everything&lt;/code&gt; 别乱点。它会把你所有节点上的缓存全部清掉，清完之后的一段时间里，所有请求都会压到源站上。我手滑点过一次，那一分钟 VPS 的负载直接飙到 8。后来我都是按 URL 精确 Purge。&lt;/p&gt;&#xA;&lt;p&gt;还有 &lt;code&gt;Vary&lt;/code&gt; 头。如果你的源站返回了 &lt;code&gt;Vary: Cookie&lt;/code&gt; 之类的东西，Cloudflare 基本就不会缓存这个响应了，因为同一个 URL 对应太多变体。静态博客一般没这个问题，但如果你在 Nginx 里加过什么奇怪的配置，值得检查一下。&lt;/p&gt;&#xA;&lt;h2 id=&#34;写在最后&#34;&gt;写在最后&#xA;&lt;/h2&gt;&lt;p&gt;这件事的性价比确实高。不用升级套餐，不用换服务器，只是把规则写对，速度就上了一个台阶。&lt;/p&gt;&#xA;&lt;p&gt;我现在给静态站做优化的顺序基本固定了。先看资源有没有带指纹，再看缓存头怎么写，最后才去考虑 Cloudflare 那层。前面两步做扎实，CDN 才帮得上忙。顺序反过来的话，你在 CDN 后台点半天，源站一个 &lt;code&gt;no-cache&lt;/code&gt; 就把你打回原形。&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
