防止点击后退按钮时表单重新提交

24
我在这里和其他地方搜索了许多帖子,但似乎找不到解决我的问题的方法。 我有一个页面显示数据库条目:database.php。可以使用表单过滤这些条目。当我过滤它们并仅显示我感兴趣的条目时,我可以点击一个条目(作为链接),该链接通过php GET将我带到该条目的页面(即“view.php?id=1”)。当我在该条目的页面上(即“view.php?id=1”)并点击后退按钮(返回到database.php),过滤表单需要确认表单重新提交。有没有办法防止这种情况发生?
以下是一些(简化的)代码示例:

Database.php:

<form>
    <select>
        <option>1</option>
        <option>2
        <option>
    </select>
    <input type="submit" name="apply_filter" />
</form>
<?php
if ( isset( $_POST[ "apply_filter" ] ) ) { // display filtered entries
    $filter = $_POST[ "filter" ];
    $q = "Select * from table where col = '" . $filter . "'";
    $r = mysql_query( $q );
} else { // display all entries
    $q = "Select * from table";
    $r = mysql_query( $q );
}
while ( $rec = mysql_fetch_assoc( $r ) ) {
    echo "<a href='view.php?id=" . $rec[ "id" ] . "'>" . $rec[ "name" ] . "</a><br />"; // this is where the link to the view.php page is...
}
?>

现在如上所述,如果我点击链接,它会带我到“view.php?id=任何内容”。在那个页面上,我只需从url获取ID来显示单个条目:

view.php:

<?php
$id = $_GET[ "id" ];
$q = "Select * from table where id = '" . $id . "'";
$r = mysql_query( $q );
while (  ) {
    // display entry
}

?>

如果我现在点击后退按钮,database.php上的表单(用于过滤数据库结果的表单)需要确认才能重新提交。这不仅非常烦人,对我也毫无用处。我该如何解决这个问题?希望我的代码示例和问题说明足够清楚。如果不行,请告诉我,我会尽力说明。

3
POST -> 服务器端302重定向 -> GET - scunliffe
我知道有很多关于这个主题的帖子。浏览了它们后,我无法解决自己的问题,所以我决定将其作为一个新问题提出。 - user1889382
你可能想使用“Post-Redirect-Get”模式,请参见https://en.wikipedia.org/wiki/Post/Redirect/Get,以及https://dev59.com/Am_Xa4cB1Zd3GeqP0WFs。 - Adriano
可能是防止后退按钮显示POST确认警报的重复问题。 - Eugen Konkov
10个回答

34

我知道这个问题很老了,但我自己也遇到了这个问题,我发现两行代码可以解决它:

header("Cache-Control: no cache");
session_cache_limiter("private_no_expire");

1
这些行代码应该添加在哪里? - user5876173
@user3663 我在所有页面上使用它,但可能只适用于界面页面,例如view.php,关于OP的问题。 - Ryan Konkolewski
我在使用session_cache_limiter时遇到了错误。我同时也在使用session_start。当我没有使用session_cache_limiter("private_no_expire"),而是使用session_start和header("Cache-Control: no cache")时,它似乎可以工作。我将其用于包含提交按钮的页面。 - Glen

9

我知道两种方法来做到这一点。简单的方法和困难的方法。

无论采用哪种方式,在处理基于状态的页面(使用 $_SESSION )时,你应该保持页面“活动”并始终掌控,可以通过以下方式防止所有页面被缓存:

<?php
//Set no caching
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
header("Cache-Control: no-store, no-cache, must-revalidate"); 
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
?>

硬编码的方法是生成一个id,并将其存储在页面上作为隐藏输入或$_SESSION cookie。 然后,将相同的id作为$_SESSION存储在服务器上。 如果它们不匹配,则一系列预编程的if else类型语句会导致在重新提交页面时不会发生任何事情(这就是单击“返回”时尝试执行的操作)。
简单的方法是如果表单成功提交,则直接将用户重定向回表单提交页面,如下所示:
header('Location: http://www.mydomain.com/redirect.php');

我希望这可以帮助你!

1
我不理解“简单的方式”。。如果用户在“查看”页面上,由于我不知道他想要查看该页面上多长时间,因此无法将其重定向。我包含了一个重定向按钮,使用户返回到表单页面;这没问题。只有当用户按下返回按钮返回到整个数据库时才会出现问题。 - user1889382
你需要从表单中提交到 Database.php,然后收集所有信息,并在脚本末尾使用 $_GET 风格的 URL 重定向用户,例如 header('Location: http://www.mydomain.com/view.php?databse=this&somethingelse=that'); - Phillip Berger

3

有一件事可能会有所帮助,那就是使您的筛选表单使用 GET 方法而不是 POST

浏览器通常会阻止自动重新提交 POST 输入,但如果使用 GET 输入,则不会这样做。此外,这将允许用户链接到您的页面并使用过滤器。


1
这个解决方案最适合用于搜索/筛选表单。对于创建/更新表单,重定向是最好的选择。 - Michał Maluga

2
header("Cache-Control: no cache");

session_cache_limiter("private_no_expire");

注意:在使用从表单提交的POST数据后,这两行代码应该放在函数的结尾处。这样,当我们回到重定向的页面时,它不会要求您重新提交页面。这将起作用。


1

我使用了如何检测用户是否通过后退按钮进入页面?中的答案来检测访问是否由浏览器的后退按钮触发,然后如果是这种情况,我使用JavaScript重新加载页面。当页面重新加载时,我的代码已经处理了相应的验证,以确保表单永远不会被提交两次。在我的情况下,重要的部分是在点击浏览器的后退按钮后重新加载表单。这是我想要应用此验证的URL中的代码:

<script type="text/javascript">
    if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
        location.reload();
    }
</script>

0

另一种解决方案是,如果/当页面重新加载时,使用 $_SESSION 检查帖子的原始性。简而言之,检查唯一或随机字符串。

在表单中,添加一个输入元素,并使用 rand() 或 microtime() 设置值:

<input type="hidden" name="formToken" value="<?php echo microtime();?>"/>

然后将PHP函数包装在if块中,以验证和解析表单数据:

if(!isset($_SESSION['formToken']) || $_POST['formToken'] !== $_SESSION['formToken'])){
       $_SESSION['formToken'] = $_POST['formToken'];
      /*continue form processing */
}

0

当我在提交/重定向后将以下代码添加到我的脚本末尾时,它对我起作用。

unset($_POST);
exit();

这么简单的问题,我却花了太长时间才弄明白。


0

虽然上面已经提到过了,但我还是要再说一遍,如果你的代码中使用了session_start()函数,那么你只需要在头文件中添加这一行代码即可:

<?php
header("Cache-Control: no cache");
?>

但如果您尚未使用session_start(),则可以在头文件中添加以下行:

<?php
header("Cache-Control: no cache");
session_cache_limiter("private_no_expire");
?>

为什么要重复回答,如果你看到“它已经在上面提到了”?此外,你从你的帖子中这里复制了你的答案。 - Elikill58

0

适用于我的解决方案是

$(document).ready( function() {
//prevent form submit on refresh or resubmit with back button
if ( window.history.replaceState ) window.history.replaceState( null, null, window.location.href );
}

-2
您需要从浏览器历史记录中删除提交的POST数据。
history.replaceState("", "", "/the/result/page")

请查看this的答案

此外,您可以遵循Post/Redirect/Get模式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接