第一页包含HTML表单。第二页 - 处理提交数据的代码。
第一页中的表单已提交。浏览器被重定向到第二页。第二页处理提交的数据。
此时,如果第2页被刷新,则会弹出“确认表单重新提交”警告。
这可以预防吗?
答案 0 :(得分:142)
人们过去常常采用两种方法:
方法1:使用AJAX +重定向
这样,您可以使用JQuery或类似于Page2的方式在后台发布表单,同时用户仍会看到显示的page1。成功发布后,您将浏览器重定向到Page2。
方法2:发布+重定向到自己
这是论坛上的常用技巧。 Page1上的表单将数据发布到Page2,Page2处理数据并执行需要完成的操作,然后对自身执行HTTP重定向。这样,浏览器记住的最后一个“动作”是第2页上的简单GET,因此在F5上不会重新提交表单。
答案 1 :(得分:21)
你需要使用PRG - 发布/重定向/获取模式,你刚刚实现了PR的P。您需要重定向。(现在您根本不需要重定向。请参阅this)
PRG是一种Web开发设计模式,可以防止一些重复的表单提交,这意味着,提交表单(发布请求1) - >重定向 - >获取(请求2)
Under the hood
重定向状态代码 - 使用HTTP 302的HTTP 1.0或使用HTTP 303的HTTP 1.1
带有重定向状态代码的HTTP响应还将在位置标题字段中提供URL。通过具有该代码的响应来邀请用户代理(例如,web浏览器),以对位置字段中指定的新URL做出第二个(否则相同的)请求。
重定向状态代码是为了确保在这种情况下,Web用户的浏览器可以安全地刷新服务器响应,而不会导致重新提交初始HTTP POST请求。
Double Submit Problem
Post/Redirect/Get Solution
答案 2 :(得分:9)
直接,你不能,这是一件好事。浏览器的警报是有原因的。这个主题应该回答你的问题:
Prevent Back button from showing POST confirmation alert
建议的两个关键变通方法是PRG模式,以及AJAX提交,然后是脚本重定位。
请注意,如果您的方法允许GET而不是POST提交方法,那么这既可以解决问题,又可以更好地适应约定。这些解决方案是根据您希望/需要POST数据提供的。
答案 3 :(得分:7)
100%确保同一表单永远不会被提交两次的唯一方法是在您发出的每个表单中嵌入一个唯一标识符,并跟踪在服务器上提交的标识符。存在的缺陷是,如果用户备份到表单所在的页面并输入新数据,则相同的表单将无效。
答案 4 :(得分:6)
答案分为两部分:
确保重复的帖子不会弄乱您服务器端的数据。为此,请在帖子中嵌入唯一标识符,以便您可以拒绝服务器端的后续请求。此消息模式在消息传递术语中称为 Idempotent Receiver 。
确保用户不会被双方提交重复提交的可能性所困扰
你在2下做的任何事情都不会完全阻止重复提交。人们可以非常快地点击,黑客无论如何都可以发帖。你总是需要1.如果你想绝对确定没有重复。
答案 5 :(得分:2)
如果使用POST数据刷新页面,浏览器将确认您的重新提交。如果使用GET数据,则不会显示该消息。保存提交后,您还可以拥有第二页,重定向到没有数据的第三页。
答案 6 :(得分:2)
我发现没人提到这个伎俩。
如果没有重定向,您仍然可以在刷新时阻止表单确认。
默认情况下,表单代码如下:
<form method="post" action="test.php">
现在,将其更改为
<form method="post" action="test.php?nonsense=1">
你会看到魔力。
我猜是因为如果网址中的GET方法(查询字符串)获得了浏览器,则浏览器不会触发确认提醒弹出窗口。
答案 7 :(得分:0)
PRG模式只能阻止页面刷新引起的重新提交。这不是100%安全的措施。
通常,我会采取以下措施防止重新提交:
客户端 - 使用javascript防止重复点击按钮,这将触发表单提交。您可以在第一次点击后禁用该按钮。
服务器端 - 我将计算提交参数的哈希并将该哈希保存在会话或数据库中,因此当收到重复提交时,我们可以检测到重复,然后对客户端进行适当的响应。但是,您可以设法在客户端生成哈希值。
在大多数情况下,这些措施有助于防止重新提交。
答案 8 :(得分:0)
我真的很喜欢@Angelin的回答。但是,如果你处理一些不实用的遗留代码,这种技术可能适合你。
位于文件顶部
// Protect against resubmits
if (empty($_POST)) {
$_POST['last_pos_sub'] = time();
} else {
if (isset($_POST['last_pos_sub'])){
if ($_POST['last_pos_sub'] == $_SESSION['curr_pos_sub']) {
redirect back to the file so POST data is not preserved
}
$_SESSION['curr_pos_sub'] = $_POST['last_pos_sub'];
}
}
然后在表单的末尾,按如下方式粘贴last_pos_sub
:
<input type="hidden" name="last_pos_sub" value=<?php echo $_POST['last_pos_sub']; ?>>
答案 9 :(得分:0)
尝试tris:
function prevent_multi_submit($excl = "validator") {
$string = "";
foreach ($_POST as $key => $val) {
// this test is to exclude a single variable, f.e. a captcha value
if ($key != $excl) {
$string .= $key . $val;
}
}
if (isset($_SESSION['last'])) {
if ($_SESSION['last'] === md5($string)) {
return false;
} else {
$_SESSION['last'] = md5($string);
return true;
}
} else {
$_SESSION['last'] = md5($string);
return true;
}
}
如何使用/示例:
if (isset($_POST)) {
if ($_POST['field'] != "") { // place here the form validation and other controls
if (prevent_multi_submit()) { // use the function before you call the database or etc
mysql_query("INSERT INTO table..."); // or send a mail like...
mail($mailto, $sub, $body); // etc
} else {
echo "The form is already processed";
}
} else {
// your error about invalid fields
}
}
字体:https://www.tutdepot.com/prevent-multiple-form-submission/
答案 10 :(得分:0)
使用js阻止添加数据:
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
答案 11 :(得分:0)
您可以使用jquery来实现
<script>
$(document).ready(function(){
window.history.replaceState('','',window.location.href)
});
</script>
这是防止由于回发而在提交后再次阻止数据的最优雅的方法。
希望这会有所帮助。