具代表性的面試主題

通用面試:如何安全使用 Request.bytes() 讀取一次性請求本文?

通用中等
Offer.cc 編輯團隊發佈 更新

題幹

你要在瀏覽器或邊緣執行環境處理二進位請求本文。平台新增 Request.bytes(),但請求本文只能消費一次。請說明何時使用、如何避免重複讀取、如何限制記憶體並設計回退。

題幹與適用場景

你要在瀏覽器或邊緣執行環境處理二進位請求本文。平台新增 Request.bytes(),但請求本文只能消費一次。請說明何時使用、如何避免重複讀取、如何限制記憶體並設計回退。

MDN 說明 Request.bytes() 回傳 Promise,成功值是請求本文的 Uint8Array;讀取請求本文會消費 body。重點是 Fetch body 生命週期、記憶體邊界與錯誤處理,不是把新方法當成所有場景的預設選擇。

面試官考察點

  • 能否解釋 body 已使用狀態,以及 bytes()arrayBuffer()json()text() 的互斥關係。
  • 能否根據請求大小與處理目標選擇完整讀取或串流讀取。
  • 能否在重試、日誌、簽章驗證與業務解析之間安排唯一讀取點。
  • 能否設計能力偵測、限制、取消、逾時與錯誤映射。
  • 能否避免把原始請求本文寫入日誌、快取或跨租戶共享物件。

需要先釐清的問題

  • 請求本文大小、來源、Content-Type、是否需要簽章驗證與目標執行環境是什麼?
  • 業務需要完整位元組陣列、增量雜湊、分片上傳還是解碼後結構?
  • 失敗重試由客戶端、閘道還是業務服務負責?請求是否可安全重播?
  • 請求本文是否包含個人資料、憑證或租戶隔離資訊?

Body 生命週期與 API 選擇

Request.bytes() 成功消費 body 後,後續再呼叫 json()text() 會失敗;反過來也一樣。若同一請求需要多個消費者,應在唯一入口讀取一次,再把受控結果傳給解析、簽章與業務層。不要把 Request 物件到處傳遞,讓多個模組爭奪讀取權。

完整讀取適合受限的小請求或需要一次性校驗的協定。大請求應優先使用 request.body 的串流讀取,在讀取過程做增量雜湊與大小檢查。bytes() 回傳 Uint8Array 方便位元組處理,但不代表讀取過程沒有記憶體峰值。

記憶體、大小限制與背壓

入口先檢查 Content-Length,但不能只相信它;分塊傳輸要在讀取時累計實際位元組,超過上限立即取消。為完整讀取設定租戶、路由與全域上限,避免多個並行請求同時配置不受控陣列。串流路徑使用背壓,消費者處理不及時就暫停讀取。

需要轉發請求時,不要為記錄或重試複製多個完整陣列。若必須重播,先把經大小限制的位元組寫入受控暫存,綁定租戶、過期時間與摘要;原始請求本文不得進入普通日誌。

簽章驗證、解析與錯誤契約

需要驗證簽章時,先確定簽章涵蓋原始位元組還是正規化結構。原始位元組應在一次讀取後同時送入驗證器與解析器,避免 JSON 重新序列化改變簽章輸入。解析失敗、簽章失敗、超限、取消與逾時應映射為不同業務錯誤,不能統一回傳「格式錯誤」。

邊緣函式可能有不同 body API;用能力偵測選擇 bytes()arrayBuffer() 或串流路徑,並在啟動時記錄執行環境能力版本。回退必須維持相同大小限制、摘要與錯誤語意,不得因舊平台而靜默放寬安全策略。

取消、逾時與重播

AbortSignal 傳給讀取與下游操作,客戶端斷線或超過截止時間時立即停止讀取並釋放參照。對帶副作用的請求,逾時後不能自動重播;需要冪等鍵、服務端去重與明確重試窗口。純校驗或查詢請求也要確認重播是否會洩露敏感資料。

閘道重試可能產生多個請求副本,因此簽章驗證、冪等鍵與稽核事件應關聯同一請求 ID。失敗回應應告訴呼叫方是否可以安全重試,不洩露內部讀取狀態或密鑰資訊。

安全與可觀測性

限制 Content-Type、請求大小、讀取時長與並行數;對壓縮請求考慮解壓後大小,防止壓縮炸彈。按租戶隔離快取與暫存物件,敏感位元組只在必要範圍存在。日誌記錄位元組數、耗時、取消原因、錯誤類別與請求摘要,不記錄內容。

監控 body 消費失敗率、超限率、p95 讀取時間、峰值記憶體、下游背壓與重試率。若 bytes() 在某執行環境的失敗率升高,切換到已驗證回退並保留告警;不能捕獲例外後再次讀取同一 body。

驗證清單與追問

測試空 body、單位元組、接近上限、超過上限、分塊傳輸、慢速客戶端、客戶端中斷、重複讀取、簽章不匹配、壓縮炸彈、並行請求、舊執行環境回退與下游逾時。驗證每條路徑都只消費一次 body,並檢查取消後沒有繼續讀取。

為什麼不能先 json() 再用 bytes() 驗簽?

第一次讀取已消費 body,且 JSON 解析與重新序列化可能改變空白、順序或編碼。應先讀取原始位元組,再用同一位元組輸入驗簽與解析。

什麼時候 bytes() 比串流讀取合適?

請求很小、記憶體上限明確、協定需要完整位元組校驗時可用。大檔案、持續上傳或高並行場景應採用串流讀取與增量處理。

如何證明回退沒有降低安全性?

對每個執行環境強制覆蓋能力路徑,比較大小限制、摘要、簽章、錯誤碼、取消與稽核事件;回退不能改變安全策略或重試邊界。

公開來源

同類題目