当保存到数据库需要很长时间时,如何防止点击双 post?

how to prevent double post on click, when it takes long time to save to db?

我的问题:

如果我有一个简单的 post 请求,我只是在编辑时更改数据库中的一些 Voodoo 项目:

  [HttpPost]
    [ValidateAntiForgeryToken]
    [SessionStateActionFilter]
    public ActionResult Edit(MonkeyJar voodooMonkey)
    {
        if (!this.service.EditMonkey(voodooMonkey))
            return RedirectToAction("Edit",voodooMonkey);

        return RedirectToAction("Index");
    }

假设 EditMonkey 需要 1.5 秒来响应,而这 1.5 秒还没有结束,用户可以向相同的编辑方法发送垃圾邮件 post 请求,因此只会保存最新的编辑。我想阻止这种情况。

我读了很多关于这个问题的资料。我当然可以在通过 jquery 提交时禁用提交按钮,但这不是一种解决问题的方法吗?在不禁用按钮的情况下是否还有其他解决方案,只需跳过 post 请求编号 2...x 并只考虑第一个?

HTTP 是无状态的。也就是说,具有相同数据的双 post 是完全有效的(根据传输)。

因此,您有 2 个选择:

  • 客户端:禁用按钮,并限制请求。这根本不是 hacky。是迄今为止最常见的解决方案。
  • 服务器端:每个会话都有某种监视器锁,因此同一个会话不能重新进入已经在执行的同一个块。

两者比较,我更喜欢客户端选项。不是 100% 安全,但 99% 是可以接受的。

双击问​​题通常在 UI 中解决,是的。如果您正在创建并控制 UI,那么使用 Javascript.

防止双击那里绝对不是 'hacky'

在我看来,您似乎想要防止有人以某种方式绕过您的 UI 代码来执行额外的点击操作。无论是 disabling/editing Javascript、糟糕的浏览器 Javascript 支持,还是其他原因。

您可以对会话状态做一些事情。如果你一次只允许一个编辑,你可以做这样的事情(伪代码):

[HttpPost]
[ValidateAntiForgeryToken]
[SessionStateActionFilter]
public ActionResult Edit(MonkeyJar voodooMonkey)
{
    //Prevent double-submit
    if (Session.IsEditActive)
    {
        //TODO: determine if you want to show an error, or just ignore the request
    }

    Session.IsEditActive = true;

    try
    {
        if (!this.service.EditMonkey(voodooMonkey))
        {
            //I'm thinking you need this line here in case the Redirect does the Thread.Abort() before the finally gets called. (Is that possible? Too lazy to test. :) Probably a race condition--I'd keep it for a guaruntee)
            Session.IsEditActive = false;
            return RedirectToAction("Edit",voodooMonkey);
        }
    }
    finally
    {
        //Ensure that we re-enable edits, even on errors.
        Session.IsEditActive = false;
    }

    return RedirectToAction("Index");
}