我制作了一个用于注册活动的小应用程序。用户输入他们的数据并单击“登录”。
现在有时人们在数据库中是双重的,完全相同的数据在彼此之后非常快速地插入了 2 次。这只能意味着有人点击了两次按钮,这导致了两个帖子的发生。
这是常见的网络问题,因为信用卡应用程序和论坛应用程序经常说:“点击一次就够了!”。
我想您可以通过检查完全相同的数据以查看帖子是否唯一来解决它,但我想知道是否还有其他方法。
这当然不计入 ASP.NET 网络表单,因为 POST 并不重要。
我制作了一个用于注册活动的小应用程序。用户输入他们的数据并单击“登录”。
现在有时人们在数据库中是双重的,完全相同的数据在彼此之后非常快速地插入了 2 次。这只能意味着有人点击了两次按钮,这导致了两个帖子的发生。
这是常见的网络问题,因为信用卡应用程序和论坛应用程序经常说:“点击一次就够了!”。
我想您可以通过检查完全相同的数据以查看帖子是否唯一来解决它,但我想知道是否还有其他方法。
这当然不计入 ASP.NET 网络表单,因为 POST 并不重要。
虽然 JavaScript 解决方案可以在单击提交按钮后禁用它,但这对禁用 JavaScript 的人没有影响。在添加 JavaScript 之前,您应该始终在没有 JavaScript 的情况下使其正常工作,否则没有意义,因为用户仍然可以通过禁用 JavaScript 来绕过检查。
如果表单出现的页面是动态生成的,您可以添加一个隐藏字段,其中包含某种序列号、散列或任何唯一内容。然后,您将进行一些服务器端验证,以检查具有该唯一值的请求是否已经进入。当用户提交表单时,将根据“使用”值列表检查唯一值。如果它存在于列表中,则它是一个欺骗请求并且可以被丢弃。如果它不存在,则将其添加到列表中并正常处理。只要确保该值是唯一的,这就保证了同一个表单不会被提交两次。
当然,如果表单所在的页面不是动态生成的,那么您需要在服务器端进行艰难的检查,以检查是否尚未提交相同的信息。
到目前为止,大多数答案都是客户端的。在服务器端,您可以在第一次生成表单时生成带有 GUID 的隐藏字段,然后在收到帖子时将该 GUID 记录为提交的表单。在进行更多处理之前检查它。
用户端的解决方案是在第一次单击后通过 Javascript 禁用提交按钮。
它有缺点,但我看到它经常在电子商务网站上使用。
但是,它永远不会取代真正的服务器端验证。
每当从服务器请求页面时,生成一个唯一的 requestToken ,将其保存在服务器端,将状态标记为未处理并将其与当前请求的页面一起传递。现在,每当页面提交发生时,从“POST”数据中获取 requestToken 并检查状态并保存数据或采取替代操作。
大多数银行应用程序都使用这种技术来防止重复“POST”。因此,这是一种经过时间验证且可靠的防止重复提交的方法。
客户端技术很有用,但您可能希望将它与一些服务器端技术结合使用。
一种方法是在表单中包含一个唯一的令牌(例如GUID或类似的),以便在处理表单时可以检查该令牌是否已被使用,从而防止重复提交。
在您的情况下,如果您有一个包含活动访问者的表格,您可能会将此标记作为一列包含在内。
正如这里的许多答案所述,仅客户端的解决方案是不够的。您需要使用服务器端故障保护。
禁用提交按钮不起作用的一个经常被忽视的原因是,用户可以简单地刷新提交目标(然后在“您确定要重新提交 POST 数据吗?”对话框上单击确定)。甚至,当您尝试将页面保存到磁盘时(例如,您尝试保存订单确认的硬拷贝),某些浏览器可能会隐式重新加载提交的页面。
这些解决方案都没有解决负载平衡服务器。
如果您有一些负载均衡器,发送一个 UUID(或任何类型的唯一编号)到服务器以存储和再次读取将无法正常工作,如果服务器不知道其他服务器,因为每个请求可能由不同的服务器处理在无状态的环境中。这些服务器需要读/写到同一个地方。
如果您有多个服务器,您将需要在服务器之间有一些共享缓存(如 Redis),以便在同一位置读取/写入唯一值(这可能是一个过度设计的解决方案,但有效)。
几乎没有人禁用 js。考虑为双击每个链接和按钮的 70 岁女性编写您的电子商务网站。您要做的就是添加一个 javascript 以防止她单击“立即订购”两次。是的 - 在服务器端检查这个也是“防御性的” - 但不要为这种情况编写代码。但是为了更好的用户界面,也可以在客户端进行。
以下是我找到的一些脚本:
//
// prevent double-click on submit
//
jQuery('input[type=submit]').click(function(){
if(jQuery.data(this, 'clicked')){
return false;
}
else{
jQuery.data(this, 'clicked', true);
return true;
}
});
和
// Find ALL <form> tags on your page
$('form').submit(function(){
// On submit disable its submit button
$('input[type=submit]', this).attr('disabled', 'disabled');
});
客户端更改是一种常用技术:
但这并不完美。这一切都依赖于可用的 JS,如果不是这样,没有后端重复检测,你仍然会得到重复。
所以我的建议是在幕后开发某种检测,然后改进你的表单以阻止 JS 的人能够重复提交。
您可以跟踪表单的提交次数,并将其与会话中带有表单的页面的唯一访问次数进行比较。
除了已经提到的许多好的技术之外,另一种简单的服务器端方法,具有需要会话的缺点,是在第一次提交时关闭会话变量。