先界定一次編輯可能覆蓋甚麼
設想一間小型零售店:一名員工修正產品尺寸,另一名員工更新送貨備註,兩人都在十時開啟同一產品表格。第一人十時零五分儲存,第二人十時零七分以舊畫面儲存。如果系統以第二份表格覆蓋整個紀錄,尺寸修正便會消失,而兩個畫面可能都顯示成功。之後即使收到投訴,看起來像輸入錯誤,真正原因卻是未有處理同時寫入。要先弄清哪些欄位會一起儲存、哪些網頁或資料傳送會使用它們,以及按一次儲存是取代整筆產品還是只改某欄,才能定出適當的衝突控制單位。
HTTP 標準為這類問題提供條件式請求。伺服器可為某個產品表示提供實體標籤 ETag;更新時把讀取時取得的標籤放在 If-Match 標頭。RFC 9110 明確指出,當多個使用者同時操作同一資源時,If-Match 可用來避免後來的寫入抹掉先前改動。伺服器須在執行修改前比較舊標籤與現有表示;條件不成立時,通常回覆 412 Precondition Failed。這跟公開目錄用 If-None-Match 進行 GET 快取驗證是不同決定:這裡要問的是員工手上的舊版本是否仍可作為寫入基礎。
讓儲存具備條件,並以原子方式執行
編輯表格載入時,應同時取得目前產品資料及版本標記,而且標記須對應儲存端點真正會修改的表示。按儲存時,連同建議改動提交該標記。伺服器要在寫入當刻,於同一個交易邊界內再次比對現有版本;只在瀏覽器 JavaScript 比對,或先讀取再進行無條件寫入,仍會有競爭空隙。HTTP 的 If-Match 採用強比較,不能把弱 ETag 當作相同保護。若後台表格沒有 HTTP 寫入介面,也可用資料庫版本欄位及條件式更新實現相同業務規則,但沒有真正傳送 If-Match 時,不應聲稱已使用該 HTTP 機制。
還要決定沒有附上版本標記時怎樣處理。若產品端點政策要求所有更新都帶條件,RFC 6585 定義了 428 Precondition Required,回覆應說明如何重新提交條件式請求。已提交標記但與現有版本不符則屬另一種情況:伺服器不可默默套用舊改動,通常回覆 412。不要把權限不足或欄位格式錯誤也統稱為編輯衝突。應先確認員工有權修改該產品、資料符合欄位規則,再按標準評估條件。稽核紀錄可記下嘗試編輯的人、產品及相關版本,但不應無需要地保存敏感表格內容。
版本控制的範圍要小心決定。為整筆產品設一個 ETag 做法簡單,即使兩人改的是不同欄位,也會提示衝突;對小型目錄而言,這可能是可接受的,因為每個改動都可見。逐欄或逐組件設定版本可減少不必要的衝突,但前提是伺服器能證明未改欄位不會被覆蓋,而且互相關連的欄位仍一致。價格、稅項顯示、存貨及優惠文字可能彼此相關,獨立合併反而會形成錯誤刊登。先用整筆紀錄保護,觀察實際衝突,再在有清楚編輯規則時細化;增加複雜度應帶來更可靠的決定。
讓員工真正能處理衝突
412 回覆只是技術上的煞停。員工介面應保留未儲存輸入,並把目前已儲存內容與此次嘗試修改的內容並排顯示。如有可靠且適合顯示的紀錄,可交代最後由誰或哪個程序修改;紀錄不全時不可憑空指名。可提供逐項複製、重新載入現行產品,或檢查合併內容後以新版本標記提交等明確選項。絕不可只替舊表格換上新標記後自動重試,否則原本被阻止的覆蓋會變成看似有意的覆蓋。處理衝突的人須看清對顧客可見資料及待處理訂單的影響,而不是再按一次儲存便算。
驗收時用兩個真正的瀏覽器工作階段開啟同一產品。第一個工作階段改一項重要欄位並儲存,第二個再嘗試提交舊表格。核實第二次請求無法抹去第一次改動,員工原本輸入仍可取回,衝突畫面亦顯示最新已保存值。價格相關、存貨相關及一般描述欄位都要試,因合併規則可能不同。另須測試漏交標記、弱標記、過期標記、產品已刪除,以及網絡逾時後重試。成功路徑則須證明員工檢查合併內容後使用新的現行標記提交,最後只留下一筆一致的產品紀錄。
回到尺寸與送貨備註的例子:員工甲修正的尺寸已成為現行版本,員工乙的新備註仍未儲存。衝突畫面列出兩者差異;乙先確認新尺寸不會改變送貨規則,然後保留甲的尺寸、加入備註,並以最新產品版本儲存。若新尺寸令原定送貨承諾無法履行,乙應交由負責同事決定,而非硬性合併。受保護的結果不只是兩個 HTTP 請求都成功,而是產品頁呈現經審核的一致資料,員工亦能交代改動過程。
讓相關工作流程保持一致
產品後台應清楚說明「儲存成功」代表甚麼。資料可能已寫入目錄資料庫,但搜尋索引、店面快取或外部平台資料流仍在更新。衝突保護只確保來源紀錄不被舊資料覆蓋,並不保證各渠道即時顯示新值。若發布屬非同步流程,介面應如實顯示待更新或已刊登狀態。若價格修正緊急,須定明由誰在受保護的寫入後核對公開頁面及外部刊登。否則員工可能把正確的 200 回覆誤當成所有顧客已看到新價格的證據。
保護機制須涵蓋自動寫入者,不只是員工。供應商夜間匯入、存貨同步或活動工具,都可能在員工開著表格時修改同一產品。每個寫入者要有明確權限及欄位範圍。若匯入程序有意取代某組欄位,員工的衝突畫面應準確指出來源,讓人檢查影響。背景程序沒有畫面,也不代表可以繞過版本檢查。另一方面,若欄位真正互不依賴,系統可採用受控合併,但依賴規則必須清楚且可測試。核心原則是,持有舊版本的一方不能無聲抹去另一方已接受的改動。
有些改動不能在瀏覽器即時合併,例如受規管的描述、合約規格或需要第二人批准的價格。可把此次草稿另外保存,只供獲授權員工查閱,清楚標示尚未發布,並交給有權決定的人。對無人處理的衝突草稿亦要訂合理保存規則,避免形成一個看不見的平行目錄。不要為了不浪費員工心血,就把失敗的修改直接複製到現行產品。介面可讓編輯取回建議文字,但是否應對顧客顯示,仍須按審批流程決定。
最後,衝突訊息要讓不熟悉 HTTP 的員工看得懂。應說明產品在他開啟後已被修改、哪些輸入尚未保存,以及下一步可安全採取甚麼行動。協定狀態碼可留在日誌及開發診斷中。演練時,讓負責目錄的同事在沒有提示下處理尺寸與送貨備註的例子,觀察他能否保留已修正尺寸,並就送貨作出有根據的決定。若員工仍不清楚哪個值會公開顯示,即使條件式請求完全正確,介面也未算完成。
進行前先確認
- 員工以舊表格提交時,系統會否提示衝突並保留現行產品?
- 員工能否對照此次輸入與最新保存值,再作出明確合併決定?


