2012-11-09 183 views
7

在RESTful SOA中,假設我通過AJAX發出POST請求,但在請求超時之前我沒有收到響應。進一步假設重新提交請求會有害。 POST不是冪等的。例如,也許我正在發佈銀行轉賬。如果我沒有得到迴應,我不知道服務器是否處理了請求。如何處理超時POST請求

假設我可以控制客戶端和服務端,最佳做法是什麼?

我最初的想法是爲包括隨機數(即,僞ID;某種唯一標識符),每個POST請求;例如也許是If-None-Match標題中的一個值。通過這種方法,客戶端可以通過編程方式重新發出具有相同僞ID的超時請求,並且服務器可以拒絕它,如果它包含重複值。

+1

如果您在某個超時後未收到響應,只是假設失敗並要求客戶端重試或中止。無論如何,服務器上的代碼顯然應該檢查相同的ID。 – alfred

+0

要明確這一點,這個僞ID不是要*資源ID - 我不是直接尋址資源。我按照預期使用POST;即發佈到資源處理程序(例如/傳輸,而不是/傳輸/ )。否則,我不會在第一時間做一個POST。 – johnr

+0

這與「[避免使用REST重複發佈](http://stackoverflow.com/q/15159274/1347968)」類似。 – siegi

回答

4

有許多的方法,我聽說過,試圖解決這個

  1. 獲取的當前狀態。

    設計的服務,這樣,如果POST失敗,客戶端可以發出對同一資源GET並根據返回的數據,就可以判斷是否成功發佈的不是。

    這種方法的問題在於POST在集合中創建新項目的情況下,客戶可能難以確定該帖子是否成功(即,我的帖子添加了該項目還是做了別人的?)

  2. 的if-match

    使用If-Match頭,以防止POST被重複。例如,如果POST正在將項目添加到集合中,並且集合當前具有ETag737060cd8c284d8af7ad3082f209582d。如果737060cd8c284d8af7ad3082f209582dIf-Match是在POST使用,那麼POST將只在集合的ETag仍然737060cd8c284d8af7ad3082f209582d,這將增加該項目,並導致新的ETag的收集成功。在此階段重複POST將僅返回412 Precondition Failed

    這種方法的問題是,當你得到一個412 Precondition Failed,你不能確定,如果你的後修飾的收集,還是別人的。

  3. POST然後把

    設計您的服務永遠不會從POST留存數據。相反,POST會創建一個臨時資源,POST內容處於「待定」狀態。這個臨時資源然後用PUT「提交」。通過這種方法,你不關心你的POST時間是否結束,只需要再次發佈POST,這次你希望得到你的臨時資源。如果PUT提交資源時間結束,你也不在乎,因爲PUT是冪等的。

    這種方法的唯一真正的缺點是管理臨時資源,並在客戶端所需的額外工作所需的額外工作。

    更新

  4. 杜撰

    使用一個隨機數(A.K.消息ID,事務ID,請求ID,相關ID)是解決此問題的常用方法;但它可能有可擴展性問題。 如果您承諾拒絕所有使用先前隨機數的POST,則需要掃描現有POST記錄以確定以前是否使用了隨機數。當你只有幾千個POST時,這並不是一個問題,但是當你擁有數百萬個時(如果你沒有以快速查詢的方式存儲這些隨機數),它可能會出現問題。

    您可以通過減少拒絕在特定時間範圍內(例如,最近24小時)內使用先前nonce的所有POST的承諾來減輕這一負擔,但是如果第一次POST超時並且客戶端在該時間段內斷開連接,那麼它們又回到了原來的位置,他們不知道第一次POST是否成功,也無法確定是否應該恢復。

+1

我提議的方式如何?你認爲這是可行的嗎? – johnr

+0

@johnr我已經更新了我的答案,覆蓋了隨機數 –

+1

+1。我個人更喜歡第三種選擇;先創建資源然後使用PUT :) –