3.4 快取與版本管理:不可變部署、Headers 設定與預覽環境#
本節目標#
上線之後真正的功課才開始:怎麼更新、怎麼快取、怎麼安全地試錯、怎麼安全地後悔。本節拆解 Pages 的不可變部署模型(每次部署成 hash 目錄)、用 _headers 與 _redirects 掌控快取與導流、善用 Preview 部署與 Branch preview,最後演練 Rollback 並檢視免費方案的檔案限制。
不可變部署:每個版本都是一個 hash 目錄#
3.1 節的理論在這裡產品化。Pages 的部署模型:
project/
├── 最新(production) ── 錨定到 v3 部署 ──── example.com
├── v3 部署(deployment hash abc123)── 完整快照,永久有效,immutable
├── v2 部署(deployment hash def456)
└── v1 部署(deployment hash 789xyz)
每次部署不是「修改伺服器上的檔案」,而是整批新檔案全部上傳,成為一個不可變(immutable)的新版本;「切換版本」只是把生產錨點從 v2 指向 v3。同一批檔案在公司數百個專案共享同一份檔案指紋雜湊 —— 去重不重傳。好處:
- 快取永不作廢:同一檔名 = 同一內容,
max-age=31536000的長快取敢放心設 - 回滾 = 把錨點指回舊版本:幾乎零延遲、零風險
- 審計完整:每個部署掛一個 commit SHA,任何歷史版本隨時可訪問
資產 hash 化:靜態優先的雙重保險#
你 build 出來的檔案已經自帶內容雜湊(Astro/Vite 預設行為):
dist/_astro/index.a8f3c1.js dist/_astro/index.9d21e0.css
加上 Pages 的版本目錄,內容尋址是兩層:檔名 hash 讓瀏覽器快取可以開到一年,版本目錄讓 CDN 端任意切換版本都不汙染舊快取。
_headers 檔:宣告式快取策略#
在專案根目錄(部署時會被吃進去)建立 public/_headers:
# 格式:<URL 樣式> 縮排一行一條 header
/*
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
/_astro/*
Cache-Control: public, max-age=31536000, immutable
/images/*
Cache-Control: public, max-age=604800
/index.html
Cache-Control: public, max-age=0, must-revalidate
設定的邏輯切分:帶內容 hash 的資產永久快取;HTML 是「路由的入口」,必須永遠拿最新——HTML 一變,它引用的新 hash 檔自然跟著變。這一條 max-age=0, must-revalidate 的 HTML + max-age=31536000, immutable 的資產,就是 Jamstack 快取佈局的標準答案(8.2 節再深化精修)。
_redirects 檔:路徑治理#
同樣放在 public/_redirects:
/old-blog/* /blog/:splat 301 # 舊網站遷址,`:splat` 保留原路徑
/readme.txt /README.md 200 # rewriting:URL 不變、回吐別的檔案
/career https://jobs.example.com/ 302 # 臨時導去外部網址
掌握三個層級即可:301(永久遷移 SEO)、302(臨時導流)、200( rewriting —— URL 不變但回吐別的資源,可用於 SPA 的 fallback)。
Preview 部署與 Branch preview#
每個部署都有永駐的獨立 URL,這是 Pages 的殺手級功能:
| 部署層 | URL 形式 | 觸發時機 |
|---|---|---|
| Production | https://example.com(即 *.pages.dev 主域) | push 到 production branch(預設 main) |
| Branch preview | https://<branch>.<project>.pages.dev | push 到其他任何分支 |
| 部署預覽(per-commit) | https://<hash>.<project>.pages.dev | 每次建置自動附贈 |
main ────┬─────┬─────┬──▶ example.com (生產)
└─ feature-留言板 ──┴────▶ https://feature-留言板.demo-pages.pages.dev
↑ 這個 URL 的快取、函式、設定全部獨立於生產
團隊協作的黃金流程:feature 分支 → push → Preview URL 給隊友/PM 看真實效果 →人到東齊 → 合併 → 生產自動上。Preview 環境的資源與生產隔離,把東西試壞了也只是試壞了一個臨時環境。
Rollback:一分鐘內的時光倒流#
事故應對演練:
- Dashboard:專案 → Deployments → 找到上一個正常的部署 → 燈籠選單 → Rollback to this deployment,即時錨定回舊版。
- 確認:
curl -I https://example.com觀察 header 或直接開瀏覽器驗證。 - 修根因:在自己的 Git branch 修好 → Review → merge → 新部署自然取代 rollback 版本。
與「在伺服器上手動還原檔案」相比:Rollback 是原子性的——不可能出現「一半是新檔一半是舊檔」的詭異中間態,因為它只是換指向,不是改內容。
免費方案的量:檔案數與單檔大小#
Pages 對每個部署的上限:
- 最多 20,000 個檔案
- 單檔最大 25 MB(壓縮前)
超限的典型肇因與解法:
| 超限情境 | 解法 |
|---|---|
node_modules 誤被打包進部署 | 一定要放 .gitignore;Pages 建置時自動忽略 |
| 世代超大的影片/模型 → 上限 | 改放 R2(第 5.3 節),HTML 裡引用 R2 URL |
| 圖片過多 | Cloudflare Images / 壓縮後再部署 |
| 純文字統計出來也超 20,000 檔 | 靜態站幾乎不會這麼大,先檢查是否不慎把整個 repo 上傳 |
小結與練習#
本節完成了靜態優先架上「更新生命周期」的閉環:不可變部署(版本目錄 + 兩層內容 hash)、_headers 定快取(資產長存、HTML must-revalidate)、_redirects 定導流、Preview URL 隔離試錯、Rollback 一鍵後悔、外加 20,000 檔案 / 25MB 單檔的免費方案邊界。
練習
- 在
public/_headers加上「/fonts/*長快取 +CSP頭」兩條設定,部署後用curl -I驗證響應頭確實生效。 - 把 hugo 帳號或網站舊路徑(如
/posts/2020/old-slug)塞進_redirects做 301,用瀏覽器或curl -L驗證跳轉。 - 開一個分支改首頁文案 → push → 進 PR → 在 PR 頁面點開 Preview URL 分享截圖給另外一個視窗模擬的隊友 → merge 回生產 → 回到 Deployments 列表 Rollback 回前一版 → 再 Rollback 回新版,體會整條生命週期。
- 思考題:若你的單一圖片快 30MB,彈性上有什麼更好的放置方式?(提示:R2 + 5.9 設定、CDN URL 生成)
下一章開始把「後端」搬上邊緣:Workers 與 Pages Functions。