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

本文关键字:何防止 双击 长时间 保存 数据库 | 更新日期: 2024-10-20 23:40:52

我的问题:

如果我有一个简单的帖子请求,我只是在编辑时更改数据库中的一些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秒还没有结束。用户可以将请求发送到相同的编辑方法,因此只保存更新的编辑。我想防止这种情况发生。

我读了很多关于这个问题的书。当然,我可以通过jquery在提交时禁用提交按钮,但这不是一种解决问题的方法吗?如果不禁用按钮,跳过第2…x个帖子请求,只考虑第一个请求,难道没有其他解决方案吗?

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

双击问题通常在UI中解决,是的。如果你正在创建并控制UI,那么使用Javascript阻止双击绝对不是"黑客"行为。

对我来说,这听起来像是你想防止有人以某种方式绕过你的UI代码来执行额外的点击操作。无论是禁用/编辑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");
}

Http是无状态的。也就是说,具有相同数据的双重帖子是完全有效的(根据运输)。

因此,这给你留下了两个选项:

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

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