2011-02-15 33 views
11

假設我們有一個客戶機/服務器的交互發生在不可靠的網絡(丟包)。客戶端的調用(通過TCP通過HTTP)服務器的REST API:客戶端服務器API模式(不可靠的網絡使用情況)

我看到以下問題:客戶端永遠不會獲得新創建的資源的ID,但服務器將創建資源。

問題:這是應用層面的行爲還是應該框架採取照顧? Web框架(特別是Rails)應該如何處理這種情況?有沒有關於這個主題的REST文章/白皮書?

回答

4

如果沒有合理的要創建重複的資源(例如產品具有相同的標題,描述等),那麼唯一標識符可以在服務器上生成,可以對創建的資源進行跟蹤,以防止重複請求正在處理。與在客戶端上生成唯一ID的Darrel's suggestion不同,這也會阻止單獨的用戶創建重複資源(您可能會也可能不會找到)。客戶可以根據他們的回覆代碼(分別爲201和303,在我的示例中)區分「創建」回覆和「重複」回覆。

僞代碼,用於產生這樣的標識符 - 在這種情況下,請求的規範表示的哈希:

func product_POST 
    // the canonical representation need not contain every field in 
    // the request, just those which contribute to its "identity" 
    tags = join sorted request.tags 
    canonical = join [request.name, request.maker, tags, request.desc] 
    id = hash canonical 

    if id in products 
     http303 products[id] 
    else 
     products[id] = create_product_from request 
     http201 products[id] 
    end 
end 

這個ID可以是或可以不是所創建的資源的URI的一部分。就我個人而言,我傾向於分別跟蹤它們 - 以額外的查找表爲代價 - 如果URI將暴露給用戶,因爲哈希值往往對人類難以記憶是醜陋和困難的。

在很多情況下,在一段時間後「過期」這些獨特的哈希也是有意義的。例如,如果您要製作匯款API,則用戶每隔幾分鐘將相同數量的金錢轉移給同一個人可能表示客戶從未收到過「成功」響應。另一方面,如果用戶每月向同一個人轉賬相同數量的金額,他們可能會支付他們的租金。 ;-)

-1

HTTP是一種無狀態協議,意味着服務器無法打開HTTP連接。所有連接都由客戶端初始化。所以你無法在服務器端解決這樣的錯誤。

我能想到的唯一解決方案:如果您知道,哪個客戶端創建了該產品,您可以爲其提供它創建的產品,如果它提取該信息。如果客戶不再與您聯繫,您將無法傳輸有關新產品的信息。

+0

我從來沒有提到服務器打開HTTP連接。這當然可能但不適用於這個用例。但我同意在客戶端可以檢索(最近修改過的)產品列表中增加一項功能可以緩解一些問題。在這種情況下,客戶端將有一種方法來驗證記錄是否已創建。編輯:增加了一個「但」..語句 – Zepplock 2011-02-15 22:45:44

5

客戶端將收到一個錯誤,當服務器不給迴應POST。客戶通常會重新發出請求,因爲他們認爲它失敗了。關於我的頭頂,我可以想到解決這個問題的兩種方法。

之一是,客戶端可以產生某種請求標識符,諸如GUID,它包括在請求中。如果服務器收到帶有重複GUID的POST請求,則它可以拒絕它。

另一種方法是用PUT代替POST來創建。如果你不能讓客戶端生成URI,那麼你可以要求服務器提供一個帶有GET的新URI,然後對該URI進行PUT。

如果你搜索類似「讓POST冪」你可能會發現一堆關於如何做到這一點其他建議。

+1

+1的GET/PUT組合 – 2011-02-22 04:32:16

+0

要允許從軟件崩潰恢復到您還需要將請求數據+ ID持久化存儲(DB,文件)並將其標記作爲「暫定」。從服務器獲得答覆時,您可以將交易標記爲完成。這實際上是通過REST進行消息隊列的基本實現 - 如果您有選擇,則應考慮使用現有的消息隊列基礎結構。 – 2011-02-28 09:22:13

1

你描述的問題歸結爲避免所謂的雙加。正如其他人所說的,你需要讓你的職位變得冪等。

這可以很容易地在框架級別實現。該框架可以保持已完成響應的緩存。這些請求必須具有請求唯一,以便任何重試都按此方式處理,而不是作爲新請求處理。

如果成功響應在客戶端的途中丟失,客戶端將重試同一請求唯一,服務器將響應其緩存響應。

您只剩下緩存的持久性,保留響應的時間等。一種方法是在給定的時間段後從服務器緩存中移除響應,這取決於您的應用程序域和流量,並且可以是作爲框架部分的可配置步驟留下。另一種方法是強制客戶發送確認。 Ack可以作爲單獨的請求發送(請注意,這些請求也可能會丟失),也可能作爲額外的數據支持實際請求。

儘管我的建議與其他人建議的類似,但我強烈建議您保持這一層網絡彈性,只做這件事,處理丟棄請求/響應,並且不允許它處理來自單獨請求的重複資源是一個應用程序級任務。合併這兩個部分將會實現所有功能,並且不會讓您明確區分責任。

不是一個簡單的問題,但如果你保持乾淨,你可以讓你的應用程序對壞的網絡更有彈性,而不會引入太多的複雜性。

對於其他人的一些相關經驗去here

祝你好運。

0

正如其他響應者指出的,這裏的基本問題是標準HTTP POST方法與其他方法不同。正在努力爲冪等POST方法建立一個標準,即Post-Once-Exactly,即POE。

現在我並不是說這對於所描述的情況下的每個人來說都是一個完美的解決方案,但是如果您正在編寫服務器和客戶端的情況,您可能可以利用一些來自POE的想法。草案在這裏:http://tools.ietf.org/html/draft-nottingham-http-poe-00

這不是一個完美的解決方案,這可能是爲什麼自草案提交以來六年沒有真正起飛。下面討論一些問題以及一些巧妙的備用選項: http://tech.groups.yahoo.com/group/rest-discuss/message/7646

相關問題