具代表性的面試主題

通用技術面試:如何設計 HTTP 內容協商並保持快取變體正確?

通用中等
OfferCC 編輯團隊發佈 更新

題幹

一個資源需要根據語言、壓縮編碼和媒體類型回傳不同表示。請設計內容協商與快取策略,說明 Vary、快取鍵、回退、隱私和故障排查如何處理。

題幹與適用場景

這道通用技術題考察 HTTP 表示、內容協商和共享快取的邊界。重點不是羅列 Accept 標頭,而是證明代理不會把一種語言或編碼的回應錯誤複用給另一個請求,同時讓回退和除錯行為可解釋。

面試官考察什麼

  • 能否區分資源 URI 與同一資源的不同表示,並理解主動協商的請求標頭。
  • 能否用 Vary 宣告影響回應的請求欄位,推導快取鍵和命中率取捨。
  • 能否設計語言、媒體類型和壓縮編碼的確定性回退,避免錯誤的 406 或串內容。
  • 能否識別 Cookie、Authorization、使用者特徵和高基數標頭帶來的共享快取與隱私風險。

回答前需要澄清的問題

先確認資源是否公開可共享,變體維度有哪些,是否允許伺服器驅動協商,客戶端能否顯式選擇語言,以及 CDN 是否支援按 Vary 分片。也要確認不支援語言的產品回退、壓縮演算法白名單、回應是否含個人化資料和可接受的快取命中率。

30 秒回答框架

我會把資源 URI 與表示選擇分開建模,按 Accept、Accept-Language 和 Accept-Encoding 的權重做確定性選擇,並在回應中宣告 Content-Type、Content-Language、Content-Encoding 與準確的 Vary。共享快取只複用同一變體鍵;個人化或高基數請求繞過共享快取。無法滿足時按產品規則回退並記錄協商結果,再用帶請求標頭的快取命中、內容校驗和隱私測試驗證。

分步驟深入解答

1. 先定義表示與協商維度

把同一 URI 看成資源的多種表示,例如 HTML 與 JSON、中文與英文、gzip 與 br。只把真正影響回應位元組或語意的請求欄位納入協商;不要因實作方便把任意 Cookie 或完整 User-Agent 都放入維度。伺服器應記錄選擇結果,使相同輸入得到可預測表示。

2. 設計權重、回退與錯誤

解析 Accept 系列中的品質因子和萬用字元,定義伺服器支援清單與優先順序。語言可按區域到基礎語言再到預設語言回退,媒體類型可提供明確的預設表示;只有沒有可接受表示且產品確實需要拒絕時才回傳 406。壓縮編碼只選擇允許的編碼,未知或不安全值不應繞過白名單。

3. 讓快取變體可計算

回應的 Vary 列出參與選擇的請求標頭,例如 Accept, Accept-Language, Accept-Encoding。快取用 URI、方法和這些欄位的正規化值形成變體鍵;正規化包括大小寫、空白和排序,不能把不同寫法無意間擴成無限鍵。若回應依賴授權、會話或使用者 Cookie,應使用私有快取或明確禁止共享快取。

4. 控制命中率、隱私與資源數量

每增加一個維度都會拆分快取並降低命中率,Accept-Language 還可能成為瀏覽器指紋訊號。公開頁面可只支援有限語言集合,把長尾映射到預設語言;個人化資料採用 private、短 TTL 或不快取。不要用 Vary: * 掩蓋不清楚的依賴,因為它會讓共享快取無法複用。

5. 設計可觀測性與驗證

日誌記錄正規化協商輸入、選中的表示、Vary、快取命中狀態和回退原因,但不要記錄完整敏感 Cookie。測試每個變體的回應標頭、壓縮解碼、跨 CDN 命中和未命中,特別驗證先請求中文再請求英文不會串內容。線上排查時對比 Age、快取狀態、Content-* 標頭和實際位元組,並用固定請求矩陣重放。

高品質示範回答

我會先列出有限的表示集合,再根據 Accept、Accept-Language 和 Accept-Encoding 的品質因子做確定性選擇。回應同時返回 Content-Type、Content-Language、Content-Encoding 和準確的 Vary,快取鍵只包含這些正規化維度。授權、會話和高基數特徵不進入共享快取;公開頁面的語言長尾回退到預設語言。沒有可接受表示時按產品規則回傳 406 或明確預設值。日誌記錄選擇、回退和命中狀態而不記錄敏感 Cookie,並用「先中文後英文、先 br 後 gzip」矩陣驗證 CDN 不會複用錯誤變體。

常見錯誤

  • 只設定 Content-Language,不在回應中宣告真正影響選擇的 Vary。
  • 把完整 Cookie、User-Agent 或任意請求標頭放進快取維度,造成命中率崩潰。
  • 看到不支援的語言就回傳 406,沒有定義區域到基礎語言和預設語言回退。
  • 讓共享快取複用帶 Authorization 或會話資料的回應。
  • 忽略壓縮編碼協商,回傳客戶端無法解碼的 Content-Encoding。
  • 只看狀態碼,不對比 Content-* 標頭、快取狀態和實際回應位元組。

追問及應對

為什麼 Vary 不能只寫 Accept-Language?

如果回應也受媒體類型或壓縮編碼影響,快取還需要知道這些維度。遺漏會讓共享快取把一個表示交給不相容的請求,產生串內容或解碼失敗。

Vary: * 什麼時候有用?

它表示選擇依賴未列出的資訊,通常會阻止共享快取複用。它可以作為保守保護,但不能替代梳理真實依賴和改用 private 快取。

如何降低 Accept-Language 帶來的鍵爆炸?

把客戶端語言映射到有限支援集合,按區域、基礎語言和預設語言回退;必要時用顯式 URL 或使用者選擇覆蓋自動協商,並監控每種變體的命中率。

協商失敗時應該回傳 406 還是預設表示?

取決於介面契約。機器介面通常需要明確錯誤,網頁可回退到預設語言或媒體類型;兩者都應在文件、回應標頭和日誌中保持一致,不能靜默回傳錯誤語意。

公開來源

同類題目

資源

產品比較

每份比較均依官方資料整理,並標示複核日期。

查看完整比較