在ASP.NET MVC中防止表单双重发布有哪些可能的方法?

时间:2009-11-13 14:57:48

标签: javascript html asp.net-mvc

在我的ASP.NET MVC应用程序的日志检查期间,我发现有些用户设法两次发布相同的表单。我试图重现它,但我失败了。无论如何,我想阻止用户两次发布相同的数据。在ASP.NET MVC中是否有任何规范的解决方案,或者我必须开发自己的自定义解决方案?

我的自定义解决方案我可以想象客户端和服务器端解决方案。在这两种情况下,你能推荐我什么吗?

4 个答案:

答案 0 :(得分:8)

通常的方法是在点击后立即禁用提交按钮。

使用jQuery这样的东西应该可以工作:

<script type="text/javascript">
    $("#myform").submit(function()
        { $("#submit-button").attr("disabled", "disabled"); });
</script>

现在仔细阅读你的问题并看到你使用ASP.NET MVC ......

双重帖子可能是因为用户在发布后刷新页面而引起的。如果您只是从帖子操作中返回一个视图:

[AcceptVerbs (HttpVerbs.Pos)]
ActionResult ProcessUserPost ()
{
    /*...*/

    return View ();
}

然后浏览器将尝试通过执行相同的步骤来重新创建页面,这意味着再次提交记住的表单。有些浏览器会显示一条警告信息(FireFox),其他浏览器会静静地显示(看Opera)。为了避免这种情况,您需要确保用户获取的页面是GET请求而不是POST的结果。

基本上,您需要执行重定向而不是返回视图。这将指示浏览器再次获取页面。

[AcceptVerbs (HttpVerbs.Pos)]
ActionResult ProcessUserPost ()
{
    /*...*/

    return RedirectToAction ("DisplayTheForm");
}

这样刷新页面不会导致发送新的POST请求。

当然,这不会阻止用户点击后退按钮返回到表单页面再次提交。但是这种情况应该在你的业务逻辑中处理,检查同一个用户对你正在做的事情的同一订单的双重提交。

答案 1 :(得分:5)

我可以想到三种方法来解决这个问题。

  1. 双重职位是非破坏性的。也就是说,在可能的情况下,使重新发布只是以使其仍然有效的方式刷新数据。对于创建某些内容的帖子(例如信用卡交易),这实际上是不可能的,但是当您基本上设置新属性时,这应该足以满足更新方法。
  2. 使用仅适用于一个操作的一次性随机数防止双重帖子。在您跟踪的页面上包含隐藏的随机数,并在看到第一个帖子后标记为已使用。检查此nonce以确保它之前未被使用过,如果有,则显示错误消息而不是采取措施。
  3. 通过检查发布数据的唯一性约束来防止破坏性操作。这实际上是(2)的变体,因为你的现时基本上是实际数据中的一些唯一值。这适用于某些创建方案,即,您无法使用相同的电子邮件地址创建重复的用户,但在数据中没有唯一字段时会失败。后者的示例可以是购买交易,其中用户可以多次购买相同的商品。

答案 2 :(得分:3)

我用来阻止双重帖子的一种技术是使用随每个帖子而变化的服务器端和客户端密钥。它的工作原理如下:

  1. 生成一个唯一的(随机)密钥 服务器并将其放入 会话以及隐藏的字段。

  2. 当用户回复第一个时 时间比较隐藏的关键 字段到会话中的键, 如果匹配,则接受输入 然后更改或删除密钥 从会话和更新 隐藏的领域也是如此。

  3. 如果是用户 设法点击两次提交 第二篇文章将失败,因为 HTML中的隐藏字段将不会 更长时间匹配会话变量 直到页面刷新。

答案 3 :(得分:2)

两步过程

先停用按钮。
这将阻止用户在浏览器等待服务器响应时提交表单两次。但你应该小心这个。当用户点击提交时,您必须首先验证您的表单(如果您使用客户端验证),并且当它有效时,我会使用此代码禁用按钮。

$(":submit, :button").attr("disabled", true);

在控制器中使用以下重定向操作结果之一
这将阻止用户在表单进行重新发送POST数据的过程后点击F5。这称为 POST-REDIRECT-GET 模式。

RedirectToAction();
RedirectToRoute();
Redirect(); // redirects to URL

修改
正如您在评论中所说,您的页面已经使用了P-R-G模式。在这种情况下,我确保实施第一步。