防止重新提交表格


107

第一页包含HTML表单。第二页-处理提交数据的代码。

第一页中的表单已提交。浏览器被重定向到第二页。第二页处理提交的数据。

此时,如果刷新第二页,则会弹出“确认表单重新提交”警报。

可以预防吗?



3
使用后重定向获取,如此处所述->> en.wikipedia.org/wiki/Post/Redirect/Get
2014年

即使没有重定向,您也可以防止这种情况。看这里
Eugen Konkov

Answers:


145

人们过去在这里采用两种方法:

方法1:使用AJAX +重定向

这样,您可以使用JQuery或类似于Page2的东西在后台发布表单,而用户仍然看到显示的page1。成功发布后,将浏览器重定向到Page2。

方法2:发布+重定向到自己

这是论坛上的常用技术。Page1上的Form将数据发布到Page2,Page2处理数据并完成需要做的事情,然后对自身进行HTTP重定向。这样,浏览器记住的最后一个“动作”是第2页上的简单GET,因此不会在F5上重新提交表单。


2
方法2的一种变体是重定向到另一个页面。例如,您发布到example.com/save.html,保存完成后,您将重定向到example.com/list.html
纪尧姆

1
通过方法1,我将使用名为BlockUI的jQuery插件让客户端知道正在发生的事情。
Shikiryu 2010年

我正在使用方法2,但是如果我刷新它,它会要求我重新提交。有与此类似的问题吗?
敏锐的

您确定HTTP重定向正常吗?打开网络检查器/ firebug /您的浏览器可以检查出站HTTP请求的所有内容,并检出HTTP调用。您应该看到第一个(发布表单数据)是通过POST方法发生的,返回的HTTP代码301具有指向其自身的Location标头,然后立即应该看到另一个HTTP查询使用GET方法到同一页面。
CodeTwice

@CodeTwice:在我的情况下,第1页发布到第2页,第2页处理数据并显示一个页面(将值传递到模板)。应该在哪里进行重定向?。该页面没有GET请求。
user1050619 2014年

24

您需要使用PRG-Post / Redirect / Get模式,并且刚刚实现了PRG的P。您需要重定向(现在,您根本不需要重定向。请参阅

PRG是一种Web开发设计模式,可防止某些重复的表单提交,这意味着,提交表单(发布请求1)->重定向->获取(请求2)

Under the hood

重定向状态代码 -HTTP 1.0和HTTP 302或HTTP 1.1和HTTP 303

具有重定向状态代码的HTTP响应还将在位置标头字段中提供URL。带有此代码的响应邀请用户代理(例如Web浏览器)对位置字段中指定的新URL进行其他请求(否则是相同的)。

重定向状态代码是为了确保在这种情况下,Web用户的浏览器可以安全地刷新服务器响应,而无需引起初始HTTP POST请求的重新提交。

Double Submit Problem

双重提交问题

Post/Redirect/Get Solution

发布/重定向/获取解决方案

资源


2
很好的解释。我想知道如果在重定向后用户单击浏览器上的后退按钮会发生什么。将再次显示“确认表单重新提交”弹出窗口。我想,即使没有再次显示确认弹出窗口,也会在页面1上再次发出具有相同数据的请求,然后再次将用户重定向到页面2。我有一系列的表单,form1,form2,form3。如何无缝地从形式“ n”返回到形式“ n-1”。随机问题:您在哪里研究PRG设计模式
Rpant 2015年

Chrome上的@Rpant发送位置标头的php文件甚至没有显示在浏览器历史记录中,因此后退按钮只是将您带回到表单。
FluorescentGreen5年

@Angelin重定向后如何获取将如何获取数据?例如,当我将一些数据发布到/ some_url并重定向到发出GET请求的/ some_url时。我如何知道响应是什么,因为/ some_url是通用的并且不包含像/ some_url / <id>这样的ID?
阿米特·特里帕蒂

@AmitTripathi,您必须创建自己。例如:POST请求可能是插入客户数据,而GET将显示插入成功的数据。通过将数据成功插入数据库后,您将根据收到的客户ID从数据库中获取该客户的数据,从而可以显示除表单数据之外的任何数据,或者重新使用客户页面的视图。
Angelin Nadar

但是我同意@Eugen Konkov解决方案
Nadar

10

直接,你做不到,那是一件好事。浏览器的警报在那里是有原因的。该线程应回答您的问题:

防止“后退”按钮显示POST确认警报

建议的两个关键解决方法是PRG模式和AJAX提交,然后进行脚本重定位。

请注意,如果您的方法允许使用GET而不是POST提交方法,那么这既可以解决问题,又可以更好地适应惯例。这些解决方案是在您想要/需要POST数据的假设下提供的。


8

100%确保同一表单永远不会提交两次的唯一方法是在您发布的每个表单中嵌入一个唯一的标识符,并跟踪在服务器上提交了哪些标识符。这里的陷阱是,如果用户备份到表单所在的页面并输入新数据,则相同的表单将无法使用。


6

答案分为两部分:

  1. 确保重复的帖子不会干扰服务器端的数据。为此,请在帖子中嵌入一个唯一标识符,以便您可以拒绝服务器端的后续请求。此模式在消息传递方面称为幂等接收器

  2. 确保用户不被双方重复提交的可能性所困扰

    • POST之后重定向到GET(POST重定向GET模式)
    • 使用javascript禁用按钮

您在2.下所做的任何操作都无法完全避免重复提交。人们可以非常快速地单击,而黑客仍然可以发布。您始终需要1.如果要绝对确定没有重复项。


2

如果您使用POST数据刷新页面,浏览器将确认您的重新提交。如果使用GET数据,则不会显示该消息。保存提交后,您也可以拥有第二页,然后重定向到没有数据的第三页。


2

好吧,我发现没人提过这个把戏。

如果没有重定向,您仍然可以在刷新时阻止表单确认。

默认情况下,表单代码如下:

<form method="post" action="test.php">

现在,将其更改为 <form method="post" action="test.php?nonsense=1">

您会看到魔术。

我猜是因为如果浏览器在url中获得GET方法(查询字符串),浏览器就不会触发确认警报弹出窗口。


2

您可以使用jquery做到这一点

<script>
   $(document).ready(function(){
   window.history.replaceState('','',window.location.href)
   });
</script>

这是在提交后由于回发而再次阻止数据的最优雅的方法。

希望这可以帮助。


0

PRG模式只能阻止由页面刷新引起的重新提交。这不是100%安全的措施。

通常,我将采取以下措施来防止重新提交:

  1. 客户端-使用javascript防止重复单击按钮,这将触发表单提交。您只需在第一次单击后禁用该按钮。

  2. 服务器端-我将根据提交的参数计算哈希值,并将该哈希值保存在会话或数据库中,因此,当收到重复的提交时,我们可以检测到重复,然后对客户端进行正确的响应。但是,您可以设法在客户端生成哈希。

在大多数情况下,这些措施可以帮助防止重新提交。


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']; ?>>

0

尝试尝试:

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/


0

使用js防止添加数据:

if ( window.history.replaceState ) {
    window.history.replaceState( null, null, window.location.href );
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.