【问题标题】:Prevent double form submissions防止双重表单提交
【发布时间】:2012-04-05 21:26:06
【问题描述】:

我有一个 ASP.NET MVC 3 应用程序,它有一个名为 Create 的发布操作:

[HttpPost]
public virtual ActionResult Create(Issues issues)
{
    if (ModelState.IsValid)
    {
        context.Issues.Add(issues);
        context.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(issues);
}

如果我错误地双击提交按钮,它会创建 2x 问题。有没有办法在不使用 javascript 和禁用按钮的情况下防止这种情况,我认为使用 RedirectToAction 的整个使用是通过使用 Post/Redirect/Get 设计模式来防止这种情况?

【问题讨论】:

  • 你能简单地添加类似 if(!context.Issues.Exists(logic)) 的东西吗?
  • 点击时禁用提交按钮!
  • 没有这种方法叫Exists吗?

标签: c# jquery asp.net-mvc asp.net-mvc-3


【解决方案1】:

简单的解决方案!

单击提交按钮时禁用它。 结束。

$('submitButtonId').click(function(){
    $(this).prop('disabled', true);
    $(this).attr('disabled', 'disabled'); // for jQuery versions < 1.6.
});

【讨论】:

  • 使用此解决方案,如果用户在点击和上传信息到服务器之间出现网络问题,则无法挽救表单中的信息。如果用户只花了 5 分钟填写表格,他们会很不高兴。更好的方法可能是仅在网络成功或失败之前禁用它。
  • @AlexAngas,禁用 javascript 后将无法正常工作。我不认为没有js的好方法。 (Shadow Wizard下面的回答是硬编码1000毫秒,远非理想,万一用户网速慢怎么办?)
【解决方案2】:

您提到的模式(Post/Redirect/Get 设计模式)防止页面刷新重复发布,因为最后一个操作是 GET,而不是 POST。

如果你想防止双击重复发帖,你可以:

1. Disable the button after click
2. Maintain a unique index on 'Issues' and look for duplicates
3. Maintain something in session that gives you an indication of a double post

也许还有更多方法...我认为禁用按钮可能是最简单的,因为无论如何您都会重定向到另一个页面。

【讨论】:

  • 这对上面的例子来说很好,但我要说的是更高级的例子,例如 Ajax.BeginForm,它只会更新页面的一部分
  • @BiffBaffBoff - 为了防止在客户端双击(AJAX POST),您可以简单地阻止 UI 直到响应返回(同步),或禁用按钮(异步),或实现某些东西服务器端来检测它。
  • 嗨,克里斯,这正是我现在所做的。在响应返回之前,我已禁用该按钮。再次感谢
【解决方案3】:

我能想到的最简单的方法是使用 Session:

if (ModelState.IsValid)
{
    DateTime now = DateTime.Now;
    if (Session["LastAdd"] == null || (now - (DateTime)Session["LastAdd"]).TotalMilliseconds > 1000)
    {
        //first time, or more than a second passed since last addition
        context.Issues.Add(issues);
        context.SaveChanges();
        Session["LastAdd"] = now;
    }
    return RedirectToAction("Index");
}

【讨论】:

  • 抱歉,我没有将会话用作 Windows 身份验证应用程序
  • @BiffBaffBoff - 开始使用Session 变量。
  • @Biff 会话变量与身份验证无关。是什么让你有这样的想法?
  • 我只是认为会话与表单身份验证一起使用
  • @Biff 不。它是任何 Web 应用程序不可或缺的一部分,从经典的 ASP 开始。 Forms Authentication 可能会使用 Session 来跟踪用户并让他保持登录状态,但就像您会说 string 仅存在于 Windows Forms 应用程序中一样。
【解决方案4】:

您可以在向用户显示表单时生成一个 IssueId,然后检查您的 Create 方法中是否存在此类 id 的问题,例如,跳过此类请求。

【讨论】:

  • 好吧,它只会创建继续附加 ID,因为 IssueId 是我的 PK 字段,因此对于创建的每个新问题,它都会有一个新 ID(2、3、4、5 等)。
【解决方案5】:

PRG 模式不会阻止这一点,因为其中的 P 动作需要时间(通常是这种情况)并且用户可以再次提交表单(通过单击或浏览器刷新),这将导致 PRG 模式“失败”。

请注意,恶意用户还可以通过快速连续运行多个 http 帖子来绕过您的所有客户端措施。

上述所有问题的解决方案是使用以下方法检查服务器端的重复提交,如我本人所述,here

为了您的方便,我引用:

“如果您在表单中使用隐藏的防伪令牌(当您 应该),您可以在首次提交时缓存防伪令牌并 如果需要,从缓存中删除令牌,或使缓存条目过期 在设定的时间后。

然后,您将能够根据缓存检查每个请求 特定表单是否已提交,如果已提交则拒绝。”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    • 1970-01-01
    • 2011-04-24
    • 2011-06-04
    相关资源
    最近更新 更多