後端面試:如何用 Expect: 100-continue 安全上傳大請求?
題干與適用場景
客戶端向物件儲存上傳數百 MB 檔案。伺服器只看請求標頭就可能發現令牌無效、配額不足或媒體類型不允許。請設計 HTTP/1.1 上傳握手,說明 Expect: 100-continue、417 回退、代理鏈、逾時、重試與監控策略。
這是後端協定與可靠性題。檔案大小和狀態碼是題設,不代表線上頻率。
面試官考察點
- 能否說明先做權限檢查如何避免無效請求本文字傳輸。
- 能否準確描述 100、最終回應與 417 的責任。
- 能否處理代理忽略 Expect、客戶端等待逾時與連線重用。
- 能否把冪等、可重播、校驗與可觀測性放在正確邊界。
回答前需要釐清的問題
- 上傳是否冪等,是否已有上傳工作階段或冪等鍵?
- 請求本文字是否可重新讀取,客戶端能否重新開啟檔案?
- 哪些閘道與物件儲存支援 informational response?
- 失敗時是否允許移除 Expect 重試,會不會產生重複物件?
- 哪些規則可只靠標頭拒絕,哪些必須讀完整正文?
30 秒回答框架
「客戶端先送帶有 Expect: 100-continue 的請求標頭。伺服器先驗證認證、長度、類型、配額與路由;能立即拒絕就回傳最終 4xx,允許接收才回傳 100 Continue。客戶端收到 100 後才送正文,等待逾時要有上限。若得到 417,且語意允許,移除 Expect 後重試;上傳命令必須搭配冪等鍵與可重讀正文。我會用代理矩陣、節省位元組、417 比例和正文中止率驗證整條鏈路。」
分步深入解答
1. 先傳送請求標頭
標頭包含認證、Content-Length、Content-Type、校驗摘要、租戶與冪等鍵,以及 Expect: 100-continue。伺服器可在未讀取正文前檢查令牌、路由、配額與靜態大小上限。規範要求伺服器判斷後送出中間回應或最終回應,不能讓客戶端無限等待。
PUT /objects/o-123 HTTP/1.1
Host: upload.example
Authorization: Bearer ...
Content-Length: 524288000
Content-Type: application/octet-stream
Idempotency-Key: up-7f2
Expect: 100-continue2. 處理允許與拒絕
允許接收時回傳 100 Continue,客戶端再傳正文。認證失敗、長度超限或配額不足時直接回傳最終狀態,例如 401、403、413 或 415,客戶端不應繼續傳送尚未傳出的正文。預檢只能涵蓋標頭可判斷的規則,最終狀態仍由完整流程決定。
3. 正確使用 417
417 Expectation Failed 表示伺服器或中介軟體不能滿足期望。客戶端可在語意允許時刪除 Expect 並重新傳送,但必須確認正文可重讀、冪等鍵不變、舊連線沒有殘餘正文。不要把所有 4xx 都當成 417,也不要自動重播不可逆的非冪等操作。
4. 處理等待、代理與連線
客戶端應為等待 100 設置有限逾時;逾時後是否直接送正文要遵循實作約定並記錄。HTTP/1.0 中介軟體可能忽略 Expect,代理也可能代發 100,因此上線前要驗證每一跳是否轉送標頭、是否吞掉 informational response、是否在最終拒絕後關閉或排空連線,避免下一個請求讀到殘留位元組。
5. 設計重試與冪等
只有正文來源可回退且業務允許重複時才重試。建立物件或扣減配額等副作用操作要使用穩定冪等鍵,讓伺服器把重試映射到同一結果。連線中斷後狀態可能未知,客戶端先查詢上傳工作階段或物件狀態,不能因未收到回應就建立第二個物件。
6. 把安全校驗放在兩層
預檢驗證認證、租戶、長度、類型與配額;接收正文後仍要校驗真實位元組數、摘要、惡意內容與儲存策略。不要只信任 Content-Length 或客戶端宣告的 MIME。日誌記錄請求 ID、預檢結果與已接收位元組數,禁止記錄令牌與檔案內容。
高品質示範回答
「我會把上傳拆成標頭決策與正文接收兩個階段。客戶端送認證、長度、類型、摘要、冪等鍵和 Expect: 100-continue。伺服器先做便宜且確定的拒絕;通過後回傳 100,客戶端才送大正文。417 只在可安全重試時觸發移除 Expect,並保持冪等鍵;等待逾時、連線中斷與代理忽略都用狀態查詢恢復。正文仍要做位元組數、摘要與內容安全校驗。我會在真實代理矩陣測試 100 延遲、417、提前 4xx、連線重用與節省位元組。」
常見錯誤
- 把 100 當成功回應 → 100 只代表可傳正文 → 等待最終 2xx 或明確失敗。
- 收到任意 4xx 都無 Expect 重試 → 可能重複副作用 → 只對 417 且業務可重播時回退。
- 無限等待 100 → 連線和請求懸掛 → 設定有限等待並記錄逾時路徑。
- 只做標頭校驗 → 損壞正文仍可入庫 → 正文階段再次校驗。
- 忽略代理差異 → 可能提前送正文或留下殘餘位元組 → 逐跳驗收並限制連線重用風險。
追問及應對
伺服器回傳 401 後客戶端已經送出部分正文怎麼辦?
伺服器按連線策略關閉或繼續讀取並丟棄正文,客戶端停止繼續傳送並標記嘗試失敗。連線重新重用前必須確認協定狀態已對齊。
為什麼不總是直接傳送正文?
小請求可以直接傳送;大請求的收益是在認證、長度或配額失敗時節省上傳位元組與儲存入口壓力。是否啟用應按請求大小、代理相容性與實作複雜度灰度。
HTTP/2 或 HTTP/3 還需要這個思路嗎?
不能假設 HTTP/1.1 的逐位元組行為完全相同。應驗證所用客戶端、閘道與伺服器如何處理 informational response、流量控制與取消;核心仍是盡早拒絕、可恢復上傳與冪等狀態。