2011-06-01 379 views
2

我有一個剃鬚刀視圖,呈現一個HTML表單,它發佈到服務器。 如果表單值是正確的,它會被保存到數據庫。 插入後,我重定向到另一個用戶可以進行進一步更改的視圖。如何防止ASP.NET MVC 3中的重複表單提交?

現在用戶可以點擊瀏覽器後退按鈕並重新提交表單以在db中創建另一個記錄。

如何防止在我的MVC應用程序中重複提交?

回答

5

解決方法之一是在窗體加載時隨機生成的窗體上放置一個隱藏的「標記」字段。當你看到這個令牌回到創建階段時,它暫時存儲在某個地方(例如,如果你使用會話的話會話)。如果您再次看到相同的表單,則可以假設同一表單已快速提交兩次。

+1

這可能要求您將記錄與記錄一起存儲並檢查重複項,或將記錄存儲在會話中,其中重複提交只能在同一個會話中捕獲。但是否則是一個很好的解 – Jay 2011-06-01 21:45:35

+0

視圖由模型(類)驅動。這是如何做的?我可以在控制器中生成一些隨機字符串,並分配給模型的某個字段,並存儲在會話中。在保存期間,我可以從模型中拉出並與會話中的值進行比較。這是怎麼做到的?如果沒有,你是否有示例代碼(非常高的水平)? – kheya 2011-06-01 22:18:25

+0

你如何生成該令牌?我很樂意使用會話或cookie。 – kheya 2011-06-01 22:59:27

2

創建一個cookie來代表該特定頁面成功時。如果使用cookie(瀏覽器現在會發送每個請求)重播它,則不知道是否允許進行新的嘗試。

+0

你在那個cookie中存儲什麼?我需要一個檢測和防止重複表單提交的解決方案 – kheya 2011-06-01 22:19:47

+1

只需要頁面名稱或操作名稱或任何內容來描述該操作。只要找到該cookie,然後在發佈(Request.Cookies [「無論」])並設置成功後保存使用Response.Cookies.Add – 2011-06-02 00:34:53

2

處理髮布請求後,將用戶重定向到另一個HttpGet操作。 因此,當用戶刷新瀏覽器時,後動作不會再被調用。

return RedirectToAction(「YourActionMethod」);

+1

你將如何處理瀏覽器後退按鈕單擊? – Dementic 2015-11-07 10:59:50

2

雖然客戶端驗證是可能的,但它不夠安全。 我不知道如果此方法適用於MVC 3,但我所做的是實現一個ActionFilterAttribute

這裏是實現:

public class PreventFrequentCallsAttribute : ActionFilterAttribute 
{ 
    public int DelayRequest = 5; 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
      var request = filterContext.HttpContext.Request;  
      var cache = filterContext.HttpContext.Cache; 

      var originationInfo = request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? request.UserHostAddress; 
      originationInfo += request.UserAgent; 
      var targetInfo = request.RawUrl + request.QueryString; 
      var hashValue = string.Join("", MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(originationInfo + targetInfo)).Select(s => s.ToString("x2"))); 

      if (cache[hashValue] != null) 
      {  
       filterContext.Controller.ViewData.ModelState.AddModelError("ExcessiveRequests", "Excessive Request Attempts Detected.");      
      } 
      else 
      { 
       cache.Add(hashValue, originationInfo, null, DateTime.Now.AddSeconds(DelayRequest), Cache.NoSlidingExpiration, CacheItemPriority.Default, null); 
      } 

      base.OnActionExecuting(filterContext); 
    } 
} 

後,在目標控制器,只需添加該屬性:

[PreventFrequentCalls(3)] 
    public PartialViewResult LogOn(LogOnViewModel model)