C# 在ASP.NET中避免双重请求的最佳实践

C# 在ASP.NET中避免双重请求的最佳实践,c#,asp.net,asp.net-mvc,C#,Asp.net,Asp.net Mvc,我有以下控制器: [HttpPost] public ActionResult SomeMethod(string foo, obj bar) { //Some Logic } 现在假设从视图中,操作是从按钮或Ajax(经过一些编辑)调用的,我不希望收到双重请求 从服务器端处理它的最佳方法是什么 更新 您首先必须定义满足以下条件的时间间隔: 双重请求的标准–Jonesopolis 让我们假设在这种情况下,当第一次和第二次呼叫之间的时间差小于1s时,会出现双重请求。注意这种方法。您将在服

我有以下控制器:

[HttpPost]
public ActionResult SomeMethod(string foo, obj bar)
{
  //Some Logic 
}
现在假设从视图中,操作是从按钮或Ajax(经过一些编辑)调用的,我不希望收到双重请求

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


更新
您首先必须定义满足以下条件的时间间隔: 双重请求的标准–Jonesopolis


让我们假设在这种情况下,当第一次和第二次呼叫之间的时间差小于1s时,会出现双重请求。注意这种方法。您将在服务器端增加最复杂的控制

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

我不认为在服务器端控制这一点是最好的方法

然而,如果你真的想要。。。看:


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

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

然而,这里有一个很大的规定,就是你必须在某处记录下来,这样做需要一段时间。可能只需要几毫秒,但这可能足以让重复请求进入,特别是当用户双击提交按钮时,这通常是导致双重提交的原因

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


防止双重提交的唯一可靠方法是使用JavaScript禁用提交时的提交按钮。然后,用户实际上只能单击一次,即使他们双击。当然,如果用户禁用JavaScript,这对您仍然没有帮助,但这种情况越来越少见。

您至少需要实现双击事件侦听器

  • 使用submitbehivar=“false”
  • OnClientClick=“this.disable='true';this.value=“请稍候”
  • 检查ASP.NET生命周期
  • 检查请求/重定向
  • 添加测试代码以查看谁负责

    如果(iPostBack) {

            if (!IsPostBack)
            {
    
    
            }
        } 
    
    }

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

    受保护的无效页面加载(对象发送方、事件参数e) {

            if (!IsPostBack)
            {
    
    
            }
        } 
    

  • 您首先必须定义满足双请求条件的时间间隔。无论给定用户、ip地址、用户代理组合何时调用该请求,您都可以将该时间间隔存储在会话\缓存\中。然后检查该缓存,如果通过的时间少于1秒,则拒绝请求(或在本例中执行您需要的操作).更有趣的是,是什么促使您在服务器端处理此问题…尽管您将“服务器端”-一般来说,这在UI上更容易处理,例如取消请求或禁用按钮。这不是万无一失的,但取决于场景,通常适用于intranet应用程序。如果要防止恶意用户滥发您的服务,则可能会重复。这是完全不同的情况。这是正确的答案。管理此问题服务器端是sillyPost/Redirect/Get模式非常常见,应该采用。当您使用令牌时,您是从服务器端执行的@Liam@Luke...可以发布/重定向/获取模式!但我认为每个表单的管理器令牌的复杂性对于防止CSRF攻击最为有用。您不能将标准ValidateAntiForgeryToken用于Post/Redirect/Get模式?正如另一个答案所建议的,我们可以从客户端发送唯一密钥,并在服务器端检查它,如果我们有唯一密钥或主键,那么它也不会从db端插入。好吧,这假设服务器实际上正在向数据库写入某些内容,这并不总是如此,但如果您是wr,则是的对于数据库,您可以有一个唯一的列,在其中存储GUID或标识POST请求的任何内容,然后第二次尝试写入相同的GUID将失败。当然,此时您需要捕获数据库错误并进行优雅的恢复。然而,这实际上只是乐观并发,还有更好的方法来实现处理该问题,例如使用rowversion列。