【问题标题】:Preventing form resubmission防止表单重新提交
【发布时间】:2011-04-24 20:18:38
【问题描述】:

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

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

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

这可以预防吗?

【问题讨论】:

标签: forms http


【解决方案1】:

人们曾经在这里采取两种方法:

方法一:使用AJAX+重定向

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

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

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

【讨论】:

  • 方法 2 的变体是重定向到另一个页面。例如,您 POST 到 example.com/save.html,一旦保存完成,您就重定向到 example.com/list.html
  • 使用方法 1,我会使用名为 BlockUI 的 jQuery 插件让客户端知道正在发生的事情。
  • 我正在使用方法 2,但如果我刷新它,它会要求我再次重新提交。有人有类似的问题吗?
  • 您确定 HTTP 重定向工作正常吗?打开网络检查器/firebug/任何你的浏览器检查传出的HTTP请求并检查HTTP调用。您应该看到第一个(发布表单数据)使用 POST 方法发生,返回 HTTP 代码 301,Location 标头指向自身,然后您应该立即看到另一个使用 GET 方法对同一页面的 HTTP 查询。
  • @CodeTwice:在我的情况下,page1 发布到 page2,page2 处理数据并显示一个页面(将值传递给模板)..重定向应该在哪里发生?...页面确实没有 GET 请求。
【解决方案2】:

您需要使用 PRG - Post/Redirect/Get 模式,并且您刚刚实现了 PRG 的 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

Source

【讨论】:

  • 很好的解释。我想知道如果用户在重定向后单击浏览器上的后退按钮会发生什么。是否会再次显示“确认表单重新提交”弹出窗口。我想即使确认弹出窗口不再显示,在第 1 页上再次发出具有相同数据的发布请求,用户将再次被重定向到第 2 页。我有一系列表单,form1,form2,form3。如何从表格“n”无缝返回到表格“n-1”。随机问题:您在哪里学习 PRG 设计模式
  • @Rpant 在 chrome 上发送位置标头的 php 文件甚至不会显示在浏览器历史记录中,因此后退按钮只是将您带回表单。
  • @Angelin 重定向后如何获取数据?例如,当我将一些数据发布到 /some_url 并重定向到发出 GET 请求的 /some_url 时。我怎么知道响应应该是什么,因为 /some_url 是通用的并且不包含像 /some_url/ 这样的 id?
  • @AmitTripathi 您必须自己创建。例如:POST 请求可能是插入客户数据,而 GET 将显示插入成功的数据。您将能够显示数据,因为它只是表单数据,或者通过在成功插入数据库后收到的客户 ID 从该客户的数据库中获取该客户来重新使用客户页面的视图。
  • 但我同意@Eugen Konkov 的解决方案
【解决方案3】:

直接,你不能,这是一件好事。浏览器的警报是有原因的。这个帖子应该回答你的问题:

Prevent Back button from showing POST confirmation alert

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

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      答案分为两部分:

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

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

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

      您在 2. 下所做的任何事情都不会完全防止重复提交。人们可以非常快速地点击,黑客无论如何都可以发帖。你总是需要 1. 如果你想绝对确定没有重复。

      【讨论】:

        【解决方案6】:

        你可以使用JQuery的replaceState方法:

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

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

        希望这会有所帮助。

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

            我发现没有人提到这个技巧。

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

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

            &lt;form method="post" action="test.php"&gt;

            现在,将其更改为 &lt;form method="post" action="test.php?nonsense=1"&gt;

            你会看到魔法。

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

            【讨论】:

              【解决方案9】:

              PRG模式只能防止页面刷新导致的重新提交。这不是 100% 安全的措施。

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

              1. 客户端 - 使用 javascript 来防止重复点击会触发表单提交的按钮。您可以在第一次单击后禁用该按钮。

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

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

              【讨论】:

                【解决方案10】:

                我真的很喜欢@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']; ?>>
                

                【讨论】:

                  【解决方案11】:

                  试试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/

                  【讨论】:

                    【解决方案12】:

                    使用js防止添加数据:

                    if ( window.history.replaceState ) {
                        window.history.replaceState( null, null, window.location.href );
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2019-03-28
                      • 2013-07-24
                      • 1970-01-01
                      • 2017-07-21
                      • 1970-01-01
                      • 2018-03-18
                      • 2012-04-05
                      • 2011-06-04
                      相关资源
                      最近更新 更多