題干與適用場景
你要為多個應用程式設計可互通的外部資料儲存服務。客戶端需要發現儲存、請求讀寫權限、建立資源並訂閱變更。請說明資源模型、HTTP 語義、驗證、並發控制、通知和回滾策略。
W3C Linked Web Storage Protocol 1.0 目前是 Working Draft,目標是讓應用程式以安全、有權限且可互通的方式存取外部儲存。規範要求透過 Link 關係發現儲存和父資源,使用 linkset 管理中繼資料,並要求中繼資料更新與資源操作保持原子性。題目考察協定邊界和失效處理,不要求把草案當作穩定標準。
面試官考察點
面試官會關注你是否把資源、權限、身分、中繼資料和通知拆成可驗證的邊界,能否正確處理 POST 重試、並發 PATCH、405/415、快取和撤銷。高品質回答還會說明 Working Draft 的不確定性,以及 OpenID Connect、SAML、自簽名身分等驗證套件應按部署場景選擇。
回答前需要釐清的問題
- 資料所有者、應用程式和儲存服務分別由誰營運,信任邊界在哪裡?
- 需要哪些操作:讀取、建立、更新、刪除、分享,還是唯讀訂閱?
- 權限是按使用者、代理、資源路徑、動作還是時間窗口授予?
- 是否要求跨區域、離線存取、稽核、撤銷和最終一致通知?
- 客戶端能否處理 Link 發現、ETag、405/415 和重試去重?
30 秒回答框架
「我會把儲存、容器、資料資源、linkset、身分和存取授權分開建模。客戶端先透過 Link 關係發現儲存和父容器,再用聲明的驗證套件取得身分,提交帶有動作、主體、目標和約束的存取請求。建立使用 POST,但用冪等鍵或客戶端去重避免重試重複;中繼資料 PATCH 必須有並發條件並與資源操作原子提交。服務用 ETag、能力標頭和結構化錯誤處理衝突,通知採用可重試的最終一致佇列。每次灰度都保留授權撤銷、舊權限版本和稽核回滾。」
分步驟深入解答
1. 建立資源和發現模型
區分 storage、container、data resource 和 linkset。GET 或 HEAD 的回應透過 Link 關係暴露儲存根、父容器、類型和 linkset;客戶端不把 URL 路徑格式當作協定契約。儲存描述還應聲明伺服器能力和支援的媒體類型,讓客戶端在傳送 PUT 或特定 PATCH 前先協商。
2. 把權限建模為可稽核授權
授權記錄至少包含 assignee、action、target、約束、簽發者、有效期和撤銷狀態。儲存服務驗證呼叫方身分與授權版本,按最小權限執行 read、create、update 或 delete。驗證套件可以按組織選擇 OpenID Connect、SAML 或自簽名身分,但身分驗證與資源授權必須分層,避免把「登入成功」當作任意資源存取權。
3. 設計建立、更新和並發語義
規範示例中 POST 建立資源並由伺服器分配最終 URI,回傳 201 和 Location;POST 不是冪等操作,客戶端重試必須使用唯一請求識別或去重表。linkset 的 PATCH 是主要中繼資料更新方式,伺服器要用 ETag、If-Match 或等價版本檢查防止遺失更新;不支援 PUT 時回傳 405,不支援媒體類型時回傳 415。
POST /alice/notes/ HTTP/2
Idempotency-Key: 7b3c...
Link: <https://www.w3.org/ns/lws#DataResource>; rel="type"
Content-Type: text/plain
meeting notes4. 保證資源與中繼資料一致
建立、容器成員關係和必要的伺服器中繼資料必須作為一個原子交易提交;失敗時不能留下已可見但沒有父關係或 linkset 的孤兒資源。跨分片時使用交易日誌或 outbox 記錄狀態,讀介面按狀態回傳 pending、committed 或 failed,避免用通知抵達順序推斷提交成功。
5. 設計通知和讀寫擴充
變更事件進入可重試的 outbox,再投遞到訂閱者 inbox;事件包含儲存、資源、動作和版本,消費者用事件 ID 去重並可透過 GET 驗證目前狀態。通知遺失時依靠重播或定期對帳恢復,通知重複時保持處理冪等。Prefer、Link 和媒體類型協商應允許客戶端逐步採用能力,而不是假設所有伺服器都支援同一 PATCH 或訂閱方案。
6. 驗證、撤銷與灰度回滾
驗證套件的金鑰輪換、令牌受眾、時鐘偏差和撤銷路徑必須納入設計。權限變更寫入帶版本的稽核日誌,撤銷在授權檢查和快取失效後生效。灰度先選擇低風險租戶,觀察 401/403、405/415、衝突率、重複建立、通知延遲和稽核完整率;任何越權或資料孤兒立即停止並恢復舊授權策略。
高品質示範回答
我會把 storage、container、data resource、linkset、身分和授權分層。客戶端透過 GET/HEAD 的 Link 關係發現儲存根、父資源、類型和 linkset,先協商伺服器能力再傳送寫操作。授權記錄包含主體、動作、目標、約束、有效期和撤銷狀態,OpenID Connect、SAML 或自簽名身分只負責證明身分,不能自動授予資源權限。POST 建立資源時回傳 201 和 Location,因為 POST 非冪等,客戶端必須帶唯一請求識別或去重;linkset PATCH 使用 ETag/If-Match 防止並發遺失更新,不支援的方法或媒體類型回傳 405/415。建立、成員關係和伺服器中繼資料原子提交,事件透過 outbox 投遞到可重試 inbox,消費者按事件 ID 去重並用 GET 對帳。灰度觀察 401/403、衝突、重複建立、通知延遲和稽核完整率;發現越權、孤兒資源或無法回滾就停止,保留舊授權版本和稽核記錄。由於規範仍是 Working Draft,最終協定與測試矩陣需要版本化。
常見錯誤
- 把 URL 路徑當作全部協定契約 → 發現和能力協商會失效 → 依賴 Link 關係、媒體類型和能力標頭。
- 無條件重試 POST → 可能建立重複資源 → 使用冪等鍵、去重記錄和最終狀態查詢。
- 只驗證登入不驗證授權 → 身分成立不代表可讀寫目標資源 → 按主體、動作、目標和約束檢查授權。
- 中繼資料和資源分開提交 → 可能產生孤兒或錯誤 linkset → 採用原子交易或可恢復 outbox。
- 假設所有伺服器支援 PUT/PATCH → 客戶端相容性脆弱 → 先發現能力,正確處理 405/415。
追問及應對
為什麼 POST 重試不能直接依賴 TCP 或 HTTP?
連線可能在伺服器提交後中斷,客戶端無法知道結果;唯一請求識別和狀態查詢才能把重試與原始提交關聯起來。
如何避免權限快取導致撤銷延遲?
授權帶版本和短 TTL,撤銷寫入稽核後主動失效相關快取;關鍵寫操作再次向授權服務確認版本。
通知遺失時怎樣恢復?
事件先寫 outbox,投遞失敗可重試;消費者保留游標並定期按資源版本對帳,必要時從事件日誌重播。
為什麼需要 linkset 的原子更新?
資源已成功但成員關係或類型中繼資料未更新,會讓發現、權限和快取看到不一致狀態;原子提交能避免半完成資源公開。
Working Draft 階段如何控制投入?
實作隔離適配層和版本化測試矩陣,只在低風險流量試驗;保留舊協定和資料遷移路徑,等規範與實作報告穩定後再擴大。