2009-01-14 72 views
16

我已經爲註冊一個事件做了一個小應用程序。用戶輸入他們的數據並點擊「登錄我」。防止雙重HTTP POST

現在有時候人們在數據庫中的數量是雙倍的,即相同的數據非常快速地相互插入2次。這隻能表示有人點擊了兩次按鈕,導致發生兩個帖子。

這是常見的網絡問題,因爲信用卡應用程序和論壇應用程序經常說:「點擊一次就夠了!」。

我想你可以通過檢查完全相同的數據來查看帖子是否是唯一的,但我不知道是否有其他方法。

這當然不算ASP.NET webforms,因爲POST並不重要。

+0

[en.wikipedia.org/wiki/Post/Redirect/Get](http://en.wikipedia.org/wiki/Post/Redirect/Get) – 2011-04-18 19:15:20

回答

21

儘管JavaScript解決方案可以在點擊後禁用提交按鈕,但這對於那些禁用了JavaScript的用戶無效。在添加JavaScript之前,您應該始終在沒有JavaScript的情況下正常工作,否則沒有意義,因爲用戶仍然可以通過禁用JavaScript來繞過檢查。

如果表單出現的頁面是動態生成的,則可以添加一個隱藏字段,其中包含某種序列號,散列或任何唯一的字段。然後你有一些服務器端的驗證,它將檢查具有該唯一值的請求是否已經進入。當用戶提交表單時,將針對「已使用」值列表檢查唯一值。如果它存在於列表中,這是一個重複請求,可以放棄。如果它不存在,則將其添加到列表中並按正常方式處理。只要你確定價值是唯一的,這保證了同樣的形式不能提交兩次。

當然,如果表單所在的頁面不是動態生成的,那麼您需要在服務器端以困難的方式來檢查是否已經提交了相同的信息。

+2

您對問題的解決方案很好。但隱藏的領域可以由客戶查看,並可以由他編輯破壞我們的應用程序,可能再次接受雙重形式。我正在尋找一個完全面向服務器的解決方案。 – 2014-09-11 08:42:07

+0

如果您有一些負載均衡器,請將UUID(或任何類型的唯一編號)發送到服務器進行存儲,如果服務器不知道其他服務器,則再次讀取將無法正常工作,因爲每個請求都可能由不同的服務器處理服務器。 – Dherik 2017-12-21 13:14:00

4

用戶端解決方案是在第一次點擊後通過Javascript禁用提交按鈕。

它有缺點,但我看到它經常用在電子商務網站上。

但是,它永遠不會取代真正的服務器端驗證。

+0

它可以作爲服務器端檢測的有用補充,因爲它可以阻止您的第二次點擊將您帶到「您雙倍張貼的白癡」頁面。不久之後重新啓用按鈕是一個不錯的主意,這樣意外的雙擊就會停止,而不會故意第二次使用。 – bobince 2009-01-14 13:01:03

0

客戶端的改變是一種常見的技術:

  • 禁用提交按鈕
  • 改變屏幕的「請稍候」屏幕
  • 如果窗體是模式,改變屏幕回到他們平常(這有利於讓東西看起來很光滑)

但它並不完美。這一切都依賴於JS的可用性,如果情況並非如此,沒有後端重複檢測,您仍會得到重複。

所以我的建議是在幕後開發某種檢測然後改善你的表單以阻止JS能夠雙重提交的人。

0

您可以跟蹤表單被提交的次數,並將其與在會話中使用表單進行的唯一訪問次數進行比較。

17

到目前爲止,大部分答案都是客戶端。在服務器端,您可以在首次生成表單時生成帶有GUID的隱藏字段,然後在收到該信息時將該GUID記錄爲提交的表單。在做更多處理之前檢查它。

+0

+1客戶端是不夠可靠的地方,尤其是在一次性密鑰方法工作得很好的地方 – annakata 2009-01-14 12:05:45

+2

(實際上,只是想添加我個人更喜歡將該密鑰放在查詢字符串中,而不是創建一個隱藏字段) – annakata 2009-01-14 12:07:43

3

客戶端技術很有用,但您可能希望將其與某些服務器端技術結合使用。

要做到這一點的一種方法是在表單中包含一個唯一標記(例如GUID或類似標記),以便在處理表單時可以檢查標記是否已被使用,從而防止雙提交。

就你而言,如果你有一個帶有事件訪問者的表,你可以將這個令牌包含在列中。

0

除了已經提到的許多優秀的技術之外,另一個簡單的服務器端方法,其缺點是需要一個會話,就是有一個會話變量在第一次提交時關閉。

3

只有客戶端解決方案是不夠的,正如許多答案中所述。您需要使用服務器端故障安全保護。

一個經常被忽視的原因是禁用提交按鈕不起作用,用戶可以簡單地刷新提交目標(並在「你確定要重新提交POST數據?」對話框)上單擊確定。甚至,當您嘗試將頁面保存到磁盤時(例如,您嘗試保存訂單確認的硬拷貝),某些瀏覽器可能會隱式地重新加載提交的頁面。

1

幾乎沒有人有js殘疾。 想想爲你的電子商務網站編碼的70歲老太太誰雙擊每個鏈接和按鈕。 所有你想要做的就是添加一個JavaScript,以防止她點擊「立即訂購」兩次。 是的 - 在服務器端檢查它也「防守」 - 但不要爲這種情況編碼。但爲了更好的UI,也可以在客戶端進行。

這裏有一些腳本,我發現:

// 
// prevent double-click on submit 
// 
    jQuery('input[type=submit]').click(function(){ 
    if(jQuery.data(this, 'clicked')){ 
     return false; 
    } 
    else{ 
     jQuery.data(this, 'clicked', true); 
     return true; 
    } 
    }); 

// Find ALL <form> tags on your page 
$('form').submit(function(){ 
    // On submit disable its submit button 
    $('input[type=submit]', this).attr('disabled', 'disabled'); 
}); 
2

每當一個頁面被從服務器請求,生成一個唯一的requestToken,將其保存在服務器端,如標記狀態NOT處理並將其與當前請求的頁面一起傳遞。現在,無論何時發生頁面提交,都可以從「POST」編輯數據中獲取requestToken,並檢查狀態並保存數據或採取其他操作。

大多數銀行應用程序使用這種技術來防止雙「POST」ing.So這是一個時間證明&防止雙重提交的可靠方法。

1

這些解決方案都不涉及負載均衡服務器。

如果您有一些負載平衡器,請將UUID(或任何類型的唯一編號)發送到服務器進行存儲,如果服務器不知道其他服務器,則再次讀取將無法正常工作,因爲每個請求都可能被處理由無狀態環境中的不同服務器提供。這些服務器需要讀/寫到同一個地方。

如果您有多個服務器,您需要在服務器之間有一些共享緩存(如Redis),以在同一地點讀取/寫入唯一值(這可能是一個過度的工程解決方案,但可行)。