海外雲在線 海外雲在線 立即諮詢

AWS企業帳號代辦 AWS CloudFront快取失效問題解決

亞馬遜雲AWS / 2026-07-01 13:56:26

前言:失效不是目的,命中才是關鍵

很多團隊把 CloudFront 的快取失效當成「修 bug」的按鈕:網站改了、資產換了,就整個失效一次。短期有效,長期卻會帶來兩種代價:回源壓力上升、同時也讓你越來越難判斷到底是「內容沒更新」還是「更新了但沒命中」。更糟的是,當問題反覆出現,你會陷入一種循環:每次都失效、每次都像在賭。

要解決 CloudFront 快取失效問題,核心其實只有三件事:第一,確認你的請求到底是命中快取還是回源;第二,找出造成命中錯誤的原因(Cache policy、請求頭、查詢字串、版本策略等);第三,用可重現的方式設計更新流程,讓你不必每次都「靠失效止血」。

下面我會用一個面向實務的方式,把排查順序、常見坑位、可落地的策略串起來。你不需要先懂 CloudFront 的所有名詞,但需要建立一個清晰的判斷框架。

第一章:你以為在失效,其實可能沒有命中問題

AWS企業帳號代辦 1. 先問:使用者看到的是舊內容,還是 404/錯誤回應?

快取相關問題通常分兩類。

第一類是「內容是舊版本」:例如 JS/CSS 還是舊的 bundle,導致前端行為不一致。這類問題多半與快取命中策略、資產路徑與版本更新方式有關。

第二類是「回應失敗」:例如某些路徑偶爾出現 404、403 或者回源錯誤。這種情況不一定是快取沒失效,也可能是源站權限、簽名策略、行為(behavior)或路徑匹配出錯。

你可以先用兩個觀察點縮小範圍:瀏覽器是否顯示舊資源的檔名(如 bundle.js)仍然相同?錯誤是特定路徑持續發生,還是所有路徑偶爾失敗?

2. 檢查是否真的「命中快取」:用請求日誌與標頭推斷

CloudFront 最有價值的資訊不是你按了哪個失效,而是「每次請求最後走到哪裡」。你要找的是類似以下資訊(不同工具呈現方式略有差異):

(1)該請求的狀態是命中(Hit)還是回源(Miss/Fetch)。
(2)回應中是否帶有 CloudFront 的標頭(例如 X-Cache 或 server timing 之類的線索)。
(3)Cache status / edge response 的細節。

如果你發現使用者看到舊內容時,實際上該請求是 Miss(回源)而且源站已回傳新內容,那就要懷疑是否是「回源後又被快取」或「回源回來的其實仍是舊」。這時你要轉去檢查源站端的檔案更新是否真的完成、版本是否正確、以及 ETag/Last-Modified 是否有變化。

反過來,如果你看到使用者的請求都是 Hit(命中)但內容看起來是舊的,那才是典型快取失效問題,需要回到策略與失效觸發點。

3. 明確「失效」與「自然過期」的差別

CloudFront 的失效(Invalidation)是你主動要求把指定路徑從邊緣快取移除;自然過期(TTL 到期)是等待原本的快取有效期結束。兩者都可能出現「你以為更新了但沒更新」的感覺。

常見情境:

(1)你更新了源站,但該資產在 CloudFront 上的 TTL 還沒到,因此仍命中舊快取。
(2)你做了失效,但失效路徑寫錯(例如忘了包含尾斜線、或匹配規則太小,導致實際資產沒被覆蓋)。
(3)該資產的 Cache policy 其實把 Query string 或 Cookie 視為快取 key 的一部分,導致你失效了一個 key,但使用者命中的其實是另一個 key。

理解這三點,排查就會從「盲失效」變成「定位失效失效」。

第二章:定位問題的四個最常見原因

原因一:Cache-Control 與源站回應的控制不一致

CloudFront 最終仍會受到源站回傳的 HTTP headers 影響(取決於你的 Cache policy 設定與是否覆寫)。如果源站在資產更新後仍回傳相同的 Cache-Control,例如仍允許長時間快取,那麼自然過期會延後,失效就變成你唯一的更新手段。

AWS企業帳號代辦 實務建議是區分兩種內容類型:

AWS企業帳號代辦 (1)版本化資產(例如 /static/app.20260701.js):可以長 TTL,因為路徑會變;失效幾乎不需要。
(2)未版本化資產(例如 /static/app.js):若路徑不變,就必須搭配合理的快取策略,否則你每次發版都要失效或縮短 TTL。

當你遇到「每次都必須失效」的情況,通常不是 CloudFront 壞,而是你把永遠不會變的路徑用來承載會變的內容。解法是讓「變」出現在路徑上,而不是依賴失效。

原因二:查詢字串、Cookie 或特定請求頭被納入快取鍵

很多團隊在設定 Cache policy 時,會忽略一點:CloudFront 是否把 Query string、Cookie、Header 納入 cache key。若有,則同一個路徑在不同參數組合下會產生不同的快取項。

舉例:

AWS企業帳號代辦 你對 /api/data 進行失效時,只寫 /api/data;但使用者實際請求是 /api/data?lang=zh-TW。如果你的 Cache policy 把 Query string 納入 key,那麼失效不會影響 ?lang=zh-TW 那個 key,使用者仍會命中舊版本。

再舉例,若 Cookie(例如會員等級)被納入 key,你可能以為失效同一個 URL 就會更新所有使用者,但實際上不同 Cookie 組合就是不同快取分身。

解法是兩步驟:第一,檢查 CloudFront 的 Cache policy(以及你用的 behavior)到底把哪些部分納入 key;第二,針對 API 或動態內容,通常更建議使用「較不依賴快取」的策略:例如降低 TTL、排除不必要的 header/cookie 或將動態路由改走不同行為。

原因三:ETag/Last-Modified 沒變,但內容其實變了

有些源站在更新檔案後,仍沒有正確更新 ETag 或 Last-Modified。雖然 CloudFront 的行為依賴快取政策,但當你做了条件回源或使用特定配置時,這會導致 CloudFront 誤以為內容未變。

尤其在你使用靜態檔案儲存(例如某些對象儲存服務)時,如果上傳方式不是「覆蓋」而是「新版本但對外仍相同標識」,可能出現 header 沒反映變更。

你需要做的不是猜,而是驗證:在同一個 URL 上,直接對源站抓取 response headers(Cache-Control、ETag、Last-Modified)。然後對照 CloudFront 回來的 headers,確認是不是已經變更。當源站 header 沒變,你失效再多次也像是在推空氣。

原因四:行為(behavior)路徑匹配不符合你的預期

CloudFront 可以用多個 behavior,依路徑模式(path pattern)套用不同的快取策略。常見錯誤是:

(1)你只對某個行為設定了短 TTL,但實際資源落在另一個行為。
(2)path pattern 寫成了太寬或太窄,導致匹配到不該匹配的 behavior。
(3)某些路徑因為尾斜線、大小寫或特殊字元導致匹配不同。

當你發現「失效了但還是舊」,第一個問題不是失效本身,而是:你失效的路徑,到底對應到的是哪個 behavior 的 cache?要把這件事搞清楚。

第三章:失效策略怎麼選,才能少踩坑

1. 先決定你失效的目的:修 bug 還是部署流程的一部分?

如果你的發佈流程已經做到了版本化路徑(例如 manifest 指向新的資產清單),那失效應該是例外,而不是每次必做。若你目前的流程仍靠固定檔名承載更新內容,那失效就會成為「部署的必須步驟」。

在這兩種模式下,失效策略完全不同。

第一種模式(版本化資產):你只需要在必要時失效 HTML 入口(例如 /index.html)或 manifest。
第二種模式(固定檔名):你可能需要失效更多路徑,甚至每次都要大範圍,代價會更高。

2. 路徑粒度要精準:寫大了浪費,寫小了無效

失效的成本與你選擇的路徑數量、範圍有關。更重要的是:你寫太精準,漏掉某些實際被請求的路徑,就會造成「看似失效但用戶仍舊」。

常見做法是根據資產規則建立失效清單:

(1)靜態資產:若固定檔名(例如 app.js),可以失效整段前綴,例如 /static/app.js 或特定類型(依你實際命名)。
(2)入口頁:通常只失效入口(例如 / 對應的 index html、以及 /index.html)。
(3)API:不建議用失效解決;應改用 cache policy 降低 TTL 或直接不快取。

你要把失效清單視為「合約」。發佈時只要合約符合你的命名規則,就不會出現偶發的漏失效。

3. 大範圍失效不是萬靈丹:時間差與回源節點會放大問題

失效不是同步立刻全世界生效。某些邊緣節點可能在一段時間內仍回傳舊快取,尤其當你遇到大量流量或回源不穩定時,可能產生「部分用戶已更新、部分用戶仍舊」的觀感。

如果你遇到這種現象,請不要直接得出「失效失敗」的結論。你可以做兩件事:

第一,觀察一段時間後命中狀態是否變化;第二,用監控追蹤回源量是否因失效而激增,導致回源延遲,使回應看起來更亂。

第四章:用設計解決失效,而不是用失效修設計

策略一:版本化路徑(最有效的工程化方式)

最穩定的作法是:讓資產內容變了,URL 也變。瀏覽器與 CloudFront 才會自然淘汰舊版本,失效頻率就會下降。

你可以用以下思路:

(1)構建產物帶 hash:例如 /static/app.hash.js
(2)HTML 或 manifest 指向新 hash 的檔案。
(3)入口 HTML 的快取策略保持可控,例如短 TTL 或版本更新時失效入口。

這樣一來,你的「更新」不是去推翻快取,而是把快取變成資產版本管理的一部分。

策略二:把動態內容與靜態資產分流

API、個人化頁面、依賴 Cookie 的資源不適合用長快取策略。你可以用 behavior 將它們分開:

(1)靜態路徑(例如 /static/*、/assets/*):長 TTL、可使用壓縮、必要時限制請求頭。
(2)動態路徑(例如 /api/*、/profile/*):短 TTL 或直接不快取,並且把 Cache key 設計得更合理(避免不必要地把 Cookie/headers 納入 key)。

分流的好處是:你不會在發佈靜態資產時把動態內容也一起推進風暴。

策略三:合理的 TTL 與一致的 Cache-Control

當你仍要用失效作為短期工具,TTL 的設計會決定你失效的頻率與影響範圍。

一個實務上常見的原則是:

(1)對版本化資產:長 TTL,甚至可設想接近「永不失效」,因為 URL 會變。
(2)對入口 HTML:短 TTL 或在發佈時失效入口。
(3)對未版本化且會變的檔案:要麼改造流程做版本化,要麼採取短 TTL,否則就只能用頻繁失效換穩定。

同時確保源站的 Cache-Control 與 CloudFront 的 Cache policy 不互相打架。你不需要追求完美,但要保持可預期。

策略四:把「更新檢查」納入發佈流程

很多團隊的發佈流程缺少一個步驟:發佈後驗證用戶端實際拿到的是新內容。你可以把驗證做成簡單但可靠的檢查。

例如:

(1)發佈後,從不同地域或至少從測試環境,抓取入口 HTML 與幾個關鍵資產 URL,確認檔案內容的 hash 是否更新。
(2)同時檢查 response headers 是否符合預期(ETag/Cache-Control/Last-Modified)。
(3)若仍看到舊內容,立即比對 CloudFront 命中狀態與失效路徑清單是否匹配。

AWS企業帳號代辦 當驗證存在,你就不會被「主觀感覺」帶著走。

第五章:排查流程模板(照做通常能定位)

步驟 1:確認影響範圍與內容類型

先列出:

(1)哪些 URL 受影響?全部還是部分?
(2)受影響的是靜態資產、入口 HTML、還是 API?
(3)用戶請求是否包含 query string 或特定 cookie?

AWS企業帳號代辦 你要把問題定性,而不是一上來就去改失效。

步驟 2:確認 CloudFront 命中狀態

找到一筆代表性請求:

(1)它回傳的內容是否與源站一致?
(2)它是 Hit 還是 Miss?如果是 Hit,那就要查快取策略與失效路徑是否吻合。

若是 Miss,你要回到源站是否真的更新,以及回源是否被某種行為條件阻擋。

步驟 3:檢查 Cache policy(快取鍵)配置

重點看:

(1)Query string 是否納入 key?
(2)Cookie 是否納入 key?納入哪些?
(3)Headers 是否納入 key?
(4)TTL 策略是由 CloudFront 決定還是由源站決定?

很多「失效沒效果」其實是失效路徑沒有覆蓋到實際的 cache key 變化。

步驟 4:核對失效路徑匹配規則

把你失效的路徑清單列出來,對照實際請求 URL。特別檢查:

(1)是否有尾斜線差異?
(2)是否包含副檔名、是否需要通配符?
(3)查詢字串是否另算?(取決於你的 cache policy 與實際請求)
(4)行為路徑是否覆蓋到你失效的那個資產?

這一步能直接把「看似玄學」變成「可計算」。

步驟 5:驗證源站 headers 與實體是否更新

最後才回到源站,驗證:

(1)內容是否已更新?
(2)ETag/Last-Modified 是否跟著變?
(3)Cache-Control 是否符合你希望的策略?

如果源站沒有變,即便你失效成功也只是在移除一個沒有更新的快取。

第六章:典型案例拆解(把問題講透)

案例一:發版後 JS 仍舊,失效後部分用戶更新

狀況:團隊每次發版都會失效 /static/app.js,但仍有部分用戶看到舊版本;刷新後又好一陣子。

AWS企業帳號代辦 排查思路:

(1)確認請求命中:發現受影響用戶請求多為 Hit。
(2)檢查是否存在 query string:前端可能在某些情境下加了 ?v= 用於追蹤或排錯。若 Cache policy 把 query 納入 key,失效 /static/app.js 不會影響 /static/app.js?v=123
(3)驗證:對比兩個 URL 是否落在不同 cache key。

解法:要嘛把 query 參數排除出 cache key,要嘛乾脆把版本 hash 放進路徑,避免使用固定檔名承載變更內容。第二種更長期。

案例二:API 更新沒生效,但你其實做了入口失效

狀況:你以為用戶看到的是舊頁,但其實是 API 數據舊。團隊只失效入口 HTML。

排查思路:

(1)確認 URL:問題 API 路徑是否被 Cache policy 快取?
(2)檢查 cache TTL:若 API 行為設為長 TTL,就會出現「頁面更新了但數據沒更新」。
(3)命中狀態:API 的請求顯示多為 Hit。

解法:把 API behavior 改成短 TTL 或不快取。若一定要快取,也要確保 cache key 設計正確,並用版本化或條件更新。

案例三:你失效了,但 404 還在

狀況:部分路徑失效後,反而出現更多 404。

排查思路:

(1)確認源站:失效觸發回源後,源站其實尚未完成上傳或權限未就緒。
(2)確認路徑:你失效的路徑包含通配符,但源站實際檔名不同步。
(3)時間差:失效讓更多請求集中回源,放大源站的不穩定。

解法:發佈流程要包含「先上傳、再切換或再失效」的順序保障。並且對失效範圍採取更精準策略,避免回源風暴。

第七章:把穩定性做進去:監控與驗證的最小集合

1. 監控回源量與錯誤率

失效本質上會增加回源。你需要監控:

(1)回源請求量是否在失效後顯著上升。
(2)回源錯誤率是否上升(例如 4xx/5xx)。
(3)延遲是否拉長。

若你監控到回源錯誤與延遲,但用戶抱怨仍是「舊內容」,你要重新判斷:是否其實是回應不穩定導致看起來像快取沒更新。

2. 建立「驗證用 URL 清單」

每次發佈後,固定抓取幾個 URL:

(1)入口 HTML。
(2)最關鍵的 JS/CSS(例如前端主檔)。
(3)如有的 manifest/版本檔。

你不需要抓很多,但要穩定、可比對。只要這些 URL 的內容 hash 或關鍵字變了,你基本就能判斷 CloudFront 快取更新已完成。

3. 把失效清單寫成可追溯的記錄

每次發佈都記錄:

(1)失效的路徑清單。
(2)發佈時間與版本號。
(3)失效請求的狀態與回源監控結果。

AWS企業帳號代辦 當問題再次出現,你不必重新解讀整個系統,你只要翻看當次記錄即可。

結語:從「失效」轉向「可預期更新」

CloudFront 的快取失效問題之所以難,是因為它同時牽涉到快取策略、請求組成、源站 headers、行為路徑匹配,以及發佈流程的順序與同步。你如果只用失效去對付症狀,短期能過,但長期只會讓系統越來越難維護。

真正可持續的解法是:用版本化路徑把「變更」變成 URL 的一部分;把動態內容與靜態資產分流;確保 Cache policy 與源站 headers 的設計一致;最後用最小集合的監控與發佈後驗證,讓你能快速、準確地定位問題。

當你把這套流程做穩,失效就會從救火工具變成可控的例外措施。你也會更清楚:每一次用戶看到的內容,究竟是因為快取策略正確,還是只是你剛好按了暫時有效的按鈕。

Telegram售前客服
客服ID
@cloudcup
联系
Telegram售后客服
客服ID
@yanhuacloud
联系