【问题标题】:Best practice to avoid double request from View in ASP.NET避免来自 ASP.NET 中视图的双重请求的最佳实践
【发布时间】:2016-11-22 14:49:34
【问题描述】:

我有以下控制器:

[HttpPost]
public ActionResult SomeMethod(string foo, obj bar)
{
  //Some Logic 
}

现在假设从 Button 或 Ajax 调用 Action 的视图(经过一些编辑),我不想收到双重请求。

从服务器端处理它的最佳方法是什么?


更新

您首先必须定义满足 双重请求的标准 - Jonesopolis

假设在这种情况下,双重请求是当第一次和第二次调用之间的时间差小于 1s 时

【问题讨论】:

  • 您首先必须定义满足双重请求标准的时间间隔
  • 您可以将给定用户、IP 地址、用户代理组合调用此请求的时间存储在 session\cache\中。然后检查该缓存,如果不到 1 秒,则拒绝请求(或在这种情况下执行您需要的操作)。更有趣的是是什么导致你在服务器端处理这个......
  • 虽然您放置了“服务器端” - 通常,这在 UI 上更容易处理,例如消除请求或禁用按钮。并非万无一失,但取决于场景,通常适用于 Intranet 应用程序。
  • 如果您想防止恶意用户向您的服务发送垃圾邮件,那就完全不同了。

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


【解决方案1】:

坦率地说,你不能,至少不能完全如此。您可以在服务器端做某些事情,但没有一个是万无一失的。一般的想法是您需要以某种方式识别 POST。最常见的方法是使用 GUID 或类似的设置隐藏输入。然后,当收到请求时,您在 某处 记录该 GUID。这可能在会话中、数据库中等。然后,在处理请求之前,您检查用于该 GUID 的任何数据存储。如果存在,则为重复 POST,如果不存在,您可以继续。

但是,这里的主要规定是您必须在某个地方记录下来,并且这样做需要一段时间。可能只有几毫秒,但这可能足以让重复请求进入,尤其是当用户双击提交按钮时,这通常是导致重复提交的原因。

Web 服务器只是在请求进入时对其进行响应,重要的是,它有多个线程,甚至可能有多个进程同时为请求提供服务。 HTTP 是一种无状态协议,因此服务器不关心客户端之前是否发出过相同的请求,因为它实际上并不知道客户端之前发出过相同的请求。如果两个重复的请求几乎同时在两个不同的线程上提供服务,那么在另一个检查它是否是重复之前,看看一个是否可以设置将另一个标识为重复的东西是一场竞赛。换句话说,大多数时候,你只是运气不好,无论你尝试在服务器端做什么来阻止重复,两个请求都会通过。

防止重复提交的唯一可靠方法是在使用 JavaScript 提交时禁用提交按钮。然后,即使双击,用户也只能有效地单击一次。当然,如果用户禁用 JavaScript,这仍然无济于事,但这种情况越来越少见。

【讨论】:

  • 正如其他答案所建议的,我们可以从客户端发送唯一键并在服务器端检查它,如果我们有唯一键或主键再次基于它,它也不会从数据库端插入。
  • 假设服务器实际上正在向数据库写入内容,但情况并非总是如此,但是是的,如果您正在写入数据库,您可以拥有一个存储 GUID 的唯一列或者任何标识 POST 请求和第二次尝试写入相同 GUID 的内容都会失败。当然,此时您需要捕获数据库错误并优雅地恢复。但是,这实际上只是乐观并发,还有更好的方法来处理它,例如使用 rowversion 列。
【解决方案2】:

看。小心这种方法。您将增加大部分复杂性以在服务器端进行控制。

首先,您需要识别多个请求何时来自同一用户。

我不认为在服务器端控制它是最好的方法。

但是,如果您真的想要...请看:https://stackoverflow.com/a/218919/2892830

建议在此链接中维护令牌列表。但是,在您的情况下,只需检查是否多次收到相同的令牌。

【讨论】:

  • 这是正确答案。管理这个服务器端很傻
  • Post/Redirect/Get 模式很常见,应该使用。
  • 当您使用令牌时,您是从服务器端进行的。 @利亚姆
  • @Luke... 可以发布/重定向/获取模式!但我认为每种形式的管理器令牌的复杂性对于防止 CSRF 攻击最有用。
  • 你不能使用标准的 ValidateAntiForgeryToken 东西和 Post/Redirect/Get 模式吗?
【解决方案3】:

你至少需要实现双击事件监听器。

  1. UseSubmitBehiviar="false"
  2. OnClientClick="this.disable='true'; this.value="请稍候";"
  3. 检查 ASP.NET 生命周期
  4. 检查请求/重定向

  1. 添加测试代码,看看谁负责

    如果(IsPostBack) {

    _CtrlName = thisPage.Request.Params.Get("__EVENTTARGET");
    
    if (_CtrlName != null && _CtrlName == myButton.ID)
    {
    
        //Do your thing
    }
    

    }

  2. 在页面加载中检查 IsPostBack 并正确使用它以防止重复请求。

    protected void Page_Load(object sender, EventArgs e) {

            if (!IsPostBack)
            {
    
    
            }
        } 
    

【讨论】:

    猜你喜欢
    • 2019-04-03
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 2010-11-28
    • 1970-01-01
    • 2012-01-25
    • 2021-05-07
    相关资源
    最近更新 更多