2015-04-24 32 views
0

假設我們有一個創建和更新會議室預訂的Web服務。更新可以改變預訂的各個方面,例如時間和房間號碼。處理由重複的POST請求導致的副作用

假設用戶與服務的網絡連接可能不可靠(例如移動網絡),並且兩個用戶A和B嘗試按順序更新相同的預訂。

用戶A發送POST請求將會議時間更改爲2pm,請求到達服務器,服務器成功處理請求。但是,由於網絡連接,返回給用戶A的響應丟失,並且用戶A認爲請求失敗。

在用戶A再次嘗試之前,用戶B發送她的請求將會議時間更改爲下午2:30,併成功並響應用戶B.

現在用戶A再次(可能是自動)重新發送相同的請求,這次請求和響應都成功了,沒有問題。換句話說,會議時間改回到下午2點。

在上面的假設情況下,用戶A的重複請求會導致用戶B的請求被覆蓋,並導致服務器端的狀態不正確。

一個可能的但天真的解決方案是爲客戶端上的每個請求設置一個ID,並且如果簡單地重新嘗試/重新發送請求,則該ID不會改變。然後在服務器端,服務器維護一組收到的請求ID並檢查重複項。

有什麼更好的技術或方法來解決這個問題?

+0

看看PRG(http://en.wikipedia.org/wiki/Post/Redirect/Get)可以幫助你。 –

回答

2

這是併發用戶的常見問題。解決此問題的一種方法是強制執行條件請求,要求客戶端發送If-Unmodified-Since標頭,並在其中嘗試更改資源的值爲Last-Modified。這保證了他們在最後一次檢查和現在之間沒有其他人改變它。在你的情況下,這會阻止A重寫B的更改。

例如,用戶A想要改變會議時間。它會發送會議資源的GET請求並保留響應標頭的值。然後,它發送POST請求If-Unmodified-Since標頭中的Last-Modified值。以您的示例爲例,此請求實際上成功,但響應丟失。

如果A立即重複請求,它將因412 Precondition Failed而失敗,因爲條件不再有效。

如果在此期間B做同樣的事情並且再次改變會議時間,當A試圖重複請求時,沒有檢查對應於B的改變的當前值Last-Modified,它也失敗,並且412 Precondition Failed

+0

感謝您的回答。請您在這種情況下詳細說明「If-Unmodified-Since」和「Last-Modified」的用法嗎?哪一邊設置哪個頭? – skyork

+0

那麼這是否意味着,在服務器端,每次有更新時都需要更新資源的時間戳(在這種情況下,每個會議的詳細信息)?當任何客戶端在If-Unmodified-Since頭域中使用自己版本的Last-Modified值發送POST請求時,服務器將根據所請求資源的存儲時間戳檢查該值。如果時間戳在'Last-Modified'值之後,那麼服務器不應該處理該請求,並且應該響應'412 Precondition Failed'。這種理解是否正確? – skyork

+1

客戶端不會發送它自己版本的'Last-Modified'。它應該發出一個GET請求,並在POST請求的If-Unmodified-Since'頭中使用該響應中返回的值。如果當前存儲的時間戳記在「If-Unmodified-Since」值之後,則服務器應該以「412 Precondition Failed」失敗。如果客戶端沒有發送'If-Unmodified-Since'頭部,服務器應該失敗,並且'428 Precondition Required'。 –