題幹與適用場景
一個 Next.js 16 電商平台有四類頁面:
/guides/[slug]:20,000 篇公開指南,每週由內容團隊更新,要求搜尋引擎穩定發現正文;/products/[id]:100 萬個公開商品頁,描述和圖片可接受最多 5 分鐘陳舊,價格與庫存必須在下單前即時確認;/search?q=:結果隨查詢、篩選和目前商品狀態變化,要求首屏可分享,但不要求把每個查詢組合收錄;/account/orders:登入使用者的私有訂單頁,資料按使用者變化,不應被共享快取或搜尋引擎收錄。
團隊希望降低來源站渲染量,同時保持公開頁可發現、互動頁回應及時。面試要求候選人給每類路由確定 主要渲染策略,再說明同一路由中哪些區域可以混用其他策略。必須交代新鮮度上限、失效觸發、失敗時 顯示什麼,以及如何證明選擇在正式環境有效。
2026 年公開前端面試專題直接把「給定頁面應選擇哪種渲染策略」和「ISR 與 SSR 如何取捨」列為 問題;獨立前端題庫也單列 CSR、SSR、SSG 與 ISR 的比較。現有搜尋結果大多停留在四行優缺點, 很少把快取失效、關鍵欄位即時校驗、外置 CDN 和故障語意放進同一答案。本題補足的正是從術語 比較走到可上線決策的部分。
面試官考察點
第一,看候選人是否先定義頁面需求。決策輸入包括公開可索引性、首屏內容、新鮮度、個人化、流量、 頁面基數、互動成本和失敗行為。只說「SSR 有利於 SEO」無法決定訂單頁 或百萬商品頁該怎麼做。
第二,看是否理解四種策略把成本放在哪裡:
| 策略 | HTML 何時產生 | 主要優勢 | 主要代價 | |---|---|---|---| | CSR | 瀏覽器執行 JavaScript 後 | 私有、強互動狀態更新直接 | 初始內容依賴腳本與資料請求,用戶端成本高 | | SSR | 每次請求時在伺服器 | 可按請求回傳新鮮或個人化 HTML | 延遲與可用性依賴渲染服務和上游,運算量隨流量成長 | | SSG | 建置時 | 靜態檔案易快取,來源站請求少 | 發布與頁面規模綁定,更新通常需要重新產生 | | ISR | 先靜態產生,隨後按時間或事件再產生 | 靜態交付與局部更新兼得 | 存在明確的陳舊窗口、失效傳播與再產生失敗語意 |
第三,看能否識別混合方案。一個商品頁可以用 ISR 提供可索引的商品描述,用用戶端請求更新目前 配送選項,並在伺服器下單介面重新校驗價格與庫存。選擇 ISR 不表示整頁每個欄位都允許陳舊;選擇 SSR 也不表示頁面不需要用戶端 JavaScript 或水合。
第四,看是否會把策略變成可驗證契約。強回答會寫出「最多陳舊多久」「誰觸發失效」「再產生失敗 顯示什麼」「快取鍵是否包含使用者或地區」「真實瀏覽器下載多少 JavaScript」,並給出建置、執行期、 快取和業務正確性的指標。
回答前需要澄清的問題
- 頁面是否公開且需要收錄? 公開正文、標題、canonical 和狀態碼應盡量出現在初始回應中;
私有訂單頁應認證、禁止共享快取,並明確 noindex 策略。
- 「即時」到底多快? 商品描述允許 5 分鐘陳舊,價格與庫存卻影響付款承諾。兩個欄位不能沿用
同一個快取 SLA。
- 內容按什麼維度變化? 語言、地區、幣別、登入狀態和實驗分組會改變快取鍵。漏掉維度會造成
錯內容甚至資料洩漏,維度過多則會打碎快取命中率。
- 頁面基數和更新分布怎樣? 100 萬個 URL 不適合每次發布全部建置;若 95% 長期沒有存取,
可以只預先產生熱門路徑,其餘首次存取時產生。
- 發布事件可靠嗎? CMS 或商品系統能否傳送帶實體 ID 的事件?若事件可能遺失,需要時間失效、
對帳掃描或手動失效作為補償。
- 平台如何部署快取? 單執行個體、多個容器、託管平台和外置 CDN 的失效傳播不同。只清除
Next.js 伺服器快取,不一定清除另一個 CDN 的副本。
- 失敗時寧可舊還是錯? 指南再產生失敗時繼續顯示上一成功版本通常合理;價格、庫存和訂單
狀態必須從權威服務確認,不能把舊快取當承諾。
- 成功門檻是什麼? 約定可索引內容完整率、TTFB/LCP/INP、快取命中率、再產生延遲、陳舊年齡、
來源站渲染 QPS、建置時長、錯誤率和下單校驗衝突率。
30 秒回答框架
「我先按公開性、每請求差異、新鮮度和頁面規模分路由。指南以 SSG 為主,發布時按路徑失效;商品 詳情用 ISR 提供可索引且低成本的主體,商品事件觸發失效,並以 5 分鐘時間失效兜底,價格與庫存 在用戶端顯示時重新整理、下單時由伺服器再次確認。搜尋結果按查詢 SSR,並避免共享包含使用者條件的 回應;私有訂單頁使用認證後的伺服器外殼和 CSR 資料更新。最後用正式環境建置驗證快取行為,監控 陳舊年齡、命中率、TTFB、LCP、JavaScript 體積、再產生失敗和業務衝突,避免只看 Lighthouse 一次分數。」
分步驟深入解答
第一步:先用決策矩陣確定每個路由的主要策略
把每類頁面放進同一張矩陣,避免從框架 API 倒推需求:
| 路由 | 主要策略 | 決策依據 | 混合部分 | |---|---|---|---| | 指南 | SSG + 按事件再產生 | 公開、更新少、正文對所有使用者相同 | 發布後按路徑失效;定期對帳 | | 商品詳情 | ISR | URL 多、公開、主體可短時陳舊 | 價格/庫存即時讀取,下單伺服器再校驗 | | 搜尋結果 | SSR | 查詢組合多、結果隨請求變化 | 瀏覽器接管篩選與後續互動 | | 私有訂單 | CSR 為主 | 按使用者變化、不需索引、互動頻繁 | 可由伺服器輸出認證外殼和首屏骨架 |
指南的「SSG + 發布失效」在執行行為上已經使用增量再產生能力,但主要內容模型仍是預先產生靜態頁。 這比給 20,000 篇正文每次請求做 SSR 更便宜,也比每次改一個錯字就完整重建更及時。建置時可以 預先產生全部指南;若數量繼續成長,則只預先產生熱門路徑,其餘按首次請求產生並快取。
商品詳情選擇 ISR,是因為主體內容公開、存取重複且允許有限陳舊。不能把「5 分鐘 revalidate」 解釋成任何情況下嚴格最多陳舊 5 分鐘:時間窗口過後,下一次請求仍可能先拿到舊頁面並觸發背景 產生;低流量頁面可能更晚才觸發,產生失敗也會延長舊版本壽命。若業務需要發布後盡快更新,商品 寫入成功後應按商品 ID 觸發失效,時間窗口只做補償。
搜尋結果的查詢空間巨大,預先產生收益低。SSR 可以在首個回應中給出與查詢一致的內容和真實狀態碼, 但快取必須區分會影響結果的公開參數;登入狀態、個人化價格等回應應標記為私有或不快取。用戶端 在首屏後繼續管理篩選、分頁和輸入狀態。
訂單頁無需用公開 HTML 換取索引收益。認證外殼可以由伺服器建立,但訂單清單和即時狀態以 CSR 讀取使用者 API,回應不得進入共享快取。CSR 只是渲染選擇,認證與授權仍由伺服器執行。
第二步:把 ISR 寫成新鮮度與失效契約
商品頁需要兩個層級的契約:
可快取主體:名稱、描述、圖片、分類
事件失效:product:{id} 更新成功後觸發
時間兜底:300 秒
失敗語意:繼續服務上一成功版本並告警
關鍵即時欄位:價格、庫存、配送資格
頁面顯示:從權威介面重新整理並標註更新時間
下單提交:伺服器重新計算並要求使用者確認變更Next.js 的 ISR 文件說明,時間窗口結束後的首次請求可以收到舊內容,同時背景開始重新產生;成功後 後續請求得到新版本。若重新產生拋錯,上一成功版本繼續從快取提供,下次請求再嘗試。因此陳舊年齡 需要監控,不能把設定值當成已經實現的業務 SLA。
Next.js 16 中,revalidateTag(tag, "max") 採用 stale-while-revalidate,適合允許短暫延遲的文章、 目錄或商品主體。需要使用者提交後立即讀到自己寫入時,Server Action 中的 updateTag 提供 read-your-writes 語意。兩者不能混成一個含糊的「清快取」按鈕;事件來源、可接受陳舊度和呼叫 環境決定使用哪一種。
還要畫清快取傳播鏈:瀏覽器、CDN、Next.js 路由快取、資料快取和上游服務可能各有 TTL。官方 CDN 指引明確提醒,Next.js 的按路徑或標籤失效不會自動清除外置 CDN 已快取的副本;若另加 CDN,必須 同時清除相應 HTML 和資料變體,或讓其 TTL 滿足同一新鮮度契約。多執行個體自行託管還要共享快取 或同步失效狀態,避免一台執行個體更新、另一台繼續提供舊內容。
第三步:分別處理 SEO、互動和故障邊界
Google 能執行 JavaScript 並使用渲染後的 HTML 建立索引,但渲染會進入佇列,其他機器人未必執行 JavaScript。公開指南和商品主體應在初始 HTML 中包含可見正文、標題、canonical、結構化資料和 正確狀態碼。不能給使用者回傳空殼 200,再靠用戶端把不存在的商品改成「未找到」;伺服器或靜態 產生階段就應回傳真實的 404。
預渲染也不自動等於快速或可互動。SSR/SSG/ISR 頁面如果傳送過多用戶端元件,仍會支付 JavaScript 下載、解析和水合成本;CSR 如果拆包合理、資料靠近使用者,也可能在登入後的導覽中表現很好。因此 同時測 TTFB、LCP、INP、長任務、下載與執行的 JavaScript,以及從可見到可互動的時間。
故障策略按資料風險分級:
- 指南和商品描述再產生失敗:繼續提供上一成功版本,顯示內容更新時間,並告警陳舊年齡;
- 搜尋上游逾時:回傳可重試錯誤或經過明確許可的短時快取,不能偽裝成「無結果」;
- 價格或庫存介面失敗:禁止確認舊值,結帳前要求重試;
- 訂單介面失敗:保留已載入頁面狀態並提示重試,不能跨使用者回退到共享快取;
- 失效事件積壓:按實體版本對帳,找出快取版本落後的頁面並補償失效。
第四步:用正式環境建置和業務指標驗收
開發模式不能證明靜態產生與 ISR 行為。先執行正式環境建置,再用正式環境伺服器驗證四類路由。 測試至少覆蓋:
- 查看建置輸出,確認預期路由是靜態、按需產生還是動態,不因一次未快取讀取意外變成 SSR。
- 連續請求同一商品,驗證快取命中;修改商品後記錄事件時間、失效時間和新 HTML 首次可見時間。
- 讓再產生依賴失敗,確認仍提供上一成功主體、錯誤被記錄,恢復後能再次產生。
- 透過不同語言、地區、幣別和登入狀態請求,確認快取鍵完整且私有回應沒有共享。
- 直接抓取初始 HTML,驗證正文、metadata、canonical 和
404;再用真實瀏覽器檢查水合與互動。 - 模擬外置 CDN 和多執行個體部署,確認失效傳播到每一層,而非只在發出事件的執行個體生效。
- 在真實頁面分布下測建置時間、來源站渲染 QPS、快取命中率、TTFB、LCP、INP 和 JavaScript 成本。
- 對比頁面顯示值與結帳權威值,監控價格/庫存衝突率,確保快取最佳化沒有改變交易正確性。
上線採用逐路由遷移。先觀察目前 SSR 流量與正確性,再把低風險指南轉為靜態;商品 ISR 先以影子 方式記錄「快取會回傳什麼」,驗證失效可靠後再服務流量。任何階段都保留按路由回退到上一策略的 開關,並以業務正確性和陳舊年齡作為回退條件。
高品質示範回答
「我不會給整個應用程式只選一個縮寫。指南公開、同質且更新少,我會建置為靜態 HTML,CMS 發布 成功後按路徑失效;這樣初始正文可索引,絕大多數請求走靜態快取。商品頁有 100 萬個 URL,所以只 預先產生熱門商品,其餘首次存取產生。商品主體使用 ISR,商品事件按 ID 失效,300 秒只做遺失事件 兜底。時間到期後的首個請求可能仍拿到舊版本並觸發背景產生,因此我會監控實體更新時間與快取產生 時間的差值,而不會承諾設定了 300 秒就一定只舊 300 秒。」
「價格、庫存和配送資格不繼承商品主體的陳舊窗口。瀏覽器顯示時從權威介面重新整理;使用者點擊 下單後,伺服器重新計算,並在價格變化時要求確認。搜尋組合過多且隨查詢變化,首屏用 SSR,後續 篩選由用戶端接管;任何包含登入狀態或個人化條件的回應都不進共享快取。訂單頁使用認證後的外殼和 CSR 資料,伺服器按使用者授權,頁面設定不收錄。」
「驗收時我會用 production build 檢查每條路由的實際渲染類型,測試快取命中、事件失效、300 秒 兜底、再產生失敗和恢復。外置 CDN 需要與 Next.js 同步清除,多個執行個體需要共享失效狀態。公開 頁抓初始 HTML 檢查正文、canonical 和狀態碼,再在真實瀏覽器測 TTFB、LCP、INP、JavaScript 成本。 最終還要比較頁面價格與結帳價格;效能通過但交易正確性下降,方案仍然失敗。」
常見錯誤與改進建議
- 按應用程式只選一種策略 → 公開頁、搜尋和私有頁需求不同 → 按路由甚至按資料區域決策。
- 把 SSR 等同於 SEO 保證 → metadata、狀態碼、canonical、可抓取連結仍可能錯誤 → **檢查初始
HTML 與抓取結果。**
- 把 CSR 說成搜尋引擎完全不可見 → Google 可以渲染 JavaScript,但存在排隊和其他機器人能力
差異 → 公開關鍵內容優先伺服器或預渲染,同時準確描述限制。
- 把
revalidate=300當硬性五分鐘 SLA → 低流量、背景產生和失敗都會延長陳舊 → **事件失效、
陳舊年齡監控與時間兜底一起使用。**
- 整頁共享一個新鮮度 → 描述允許短時舊,價格與庫存不能直接承諾 → **按風險拆分資料並在
交易邊界重新確認。**
- 只清 Next.js 快取 → 外置 CDN 或其他執行個體仍可能有舊副本 → 畫出所有快取層並驗證傳播。
- 認為預渲染必然更快 → 大量 JavaScript、水合和慢上游仍會拖慢體驗 → **同時測網路、主執行緒、
Web Vitals 與伺服器指標。**
- 只在開發模式測試 ISR → 開發行為不能代表正式環境快取 → **使用 production build 和正式環境
伺服器執行命中、失效與故障測試。**
- 用舊頁面掩蓋所有錯誤 → 搜尋空結果、舊價格和跨使用者訂單會造成錯誤決策或洩漏 → **按資料
風險定義 stale-if-error。**
延伸追問
如果商品更新後必須在 10 秒內全球可見,ISR 還能用嗎?
可以保留 ISR,但必須把 10 秒寫成端到端失效 SLO:商品交易成功後可靠發出帶版本的事件,所有 Next.js 執行個體同步標籤失效,外置 CDN 同時清除,探針從多個地區檢查新版本。時間再驗證只能兜底, 不能單獨保證 10 秒。若清理鏈無法達到目標,則對該欄位使用動態讀取或更短、可證明的快取路徑。
靜態產生 100 萬個商品為什麼可能有問題?
全量產生會把建置時間、產物和發布風險與頁面基數綁定,其中大量長尾頁可能從未被存取。可以只 預先產生高流量商品,其餘首次請求時產生並快取;同時控制並行產生、防止熱門事件造成再產生風暴, 並保留不存在商品的可靠 404。
SSR 回應能否放進 CDN?
能否共享取決於回應是否對所有快取鍵維度相同,而不是取決於「SSR」這個名字。公開搜尋結果若鍵 完整且允許短時陳舊,可以謹慎設定共享快取;包含 Cookie、使用者權限、個人化價格或實驗分組的 回應應私有或不快取。必須測試 Vary、快取鍵和登出後的跨使用者隔離。
RSC、串流 SSR 和 PPR 會讓四分法失效嗎?
它們讓同一路由可以更細地組合靜態與動態工作,但沒有消除決策輸入。仍要回答內容在哪裡執行、 初始 HTML 有什麼、資料快取多久、用戶端收到多少 JavaScript、動態區域失敗時如何降級。面試中先 把 CSR/SSR/SSG/ISR 的交付與新鮮度說清,再說明 RSC、串流輸出或部分預渲染如何最佳化具體區域。
如何防止快取失效風暴?
按實體聚合重複事件,用版本號丟棄過時事件,為再產生設定並行上限與抖動,並讓同一快取鍵只有一個 產生者。監控佇列深度、產生時長、失敗率和陳舊年齡;若積壓擴大,優先保證價格庫存等關鍵動態讀取, 商品主體可以繼續提供上一成功版本。