刷新页面时如何防止表单重新提交(F5/CTRL + R)

use*_*510 118 html php forms post form-submit

我有一个简单的表单,将文本提交到我的SQL表.问题是,在用户提交文本后,他们可以刷新页面并再次提交数据,而无需再次填写表单.我可以在提交文本后将用户重定向到另一个页面,但我希望用户保持在同一页面上.

我记得读过一些关于为每个用户提供一个唯一的会话ID并将其与另一个值进行比较的方法,这个值解决了我遇到的问题,但我忘记了它的位置.

Kev*_*erw 85

使用发布/重定向/获取模式.http://en.wikipedia.org/wiki/Post/Redirect/Get

通过我的网站,我将在cookie或会话中存储消息,在帖子后重定向,读取cookie /会话,然后清除该会话或cookie变量的值.

  • 如果你使用PRG模式,那么你实际上是否正确地离开了页面?问题是如何在不重定向时让事情发挥作用? (19认同)
  • 使用 PRG,你会失去上下文,这对我来说是一个糟糕的解决方案。我们不应该这样做。 (3认同)
  • 没有回答问题。不知道为什么这是被接受的答案。 (2认同)

dtb*_*ker 80

我还想指出,您可以使用javascript方法,window.history.replaceState以防止重新提交刷新和后退按钮.

<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>
Run Code Online (Sandbox Code Playgroud)

这里的概念证明:https://dtbaker.net/files/prevent-post-resubmit.php

我仍然会推荐Post/Redirect/Get方法,但这是一个新颖的JS解决方案.

  • 我猜想,任何使用没有 javascript 的浏览器的人仍然会遇到同样的问题。也许 /sf/answers/2713769831/ 更合适。 (4认同)
  • 我认为仅使用客户端代码来操纵网站的安全性和安全性——这是一个很大的禁忌。服务器应防止误用。客户端代码应该只是一个有用的附录。 (3认同)
  • 谢谢,@dtbaker,太棒了:) (2认同)
  • Tks,这对我来说是完美的工作,它只需要创建 404 页面避免用户误解 (2认同)
  • 它在 safari 中不起作用,它更改了 href 但仍然保留要提交的发布请求的数据 (2认同)

Tan*_*tta 24

这种方法对我很有效,我认为这是完成这项工作的最简单的方法。

一般的想法是在表单提交后将用户重定向到其他一些页面,这将在页面刷新时停止表单重新提交。尽管如此,如果您需要在表单提交后将用户保持在同一页面上,您可以通过多种方式来实现,但这里我描述的是 JavaScript 方法。


JavaScript 方法

这种方法非常简单,一旦提交表单,就会阻止在刷新时要求重新提交表单的弹出窗口。只需将这行 JavaScript 代码放在文件的页脚,就可以看到“魔法”。

<script>
if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}
</script>
Run Code Online (Sandbox Code Playgroud)


Moo*_*oob 16

您应该使用Post Redirect Get模式来处理这个问题,但是如果您以某种方式最终处于PRG不可行的位置(例如,表单本身位于include,防止重定向),您可以散列一些请求参数根据内容创建一个字符串,然后检查您是否已经发送过它.

//create digest of the form submission:

    $messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']);

//and check it against the stored value:

    $sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:'';

    if($messageIdent!=$sessionMessageIdent){//if its different:          
        //save the session var:
            $_SESSION['messageIdent'] = $messageIdent;
        //and...
            do_your_thang();
    } else {
        //you've sent this already!
    }
Run Code Online (Sandbox Code Playgroud)


Sav*_*voo 13

你可以通过会话变量Like来进行表单重新提交

首先,你必须在表格页面上设置文本框中的rand()和$ _SESSION ['rand']

<form action="" method="post">
  <?php
   $rand=rand();
   $_SESSION['rand']=$rand;
  ?>
 <input type="hidden" value="<?php echo $rand; ?>" name="randcheck" />
   Your Form's Other Field 
 <input type="submit" name="submitbtn" value="submit" />
</form>
Run Code Online (Sandbox Code Playgroud)

用文本框$ _POST ['randcheck']检查$ _SESSION ['rand']之后的值

if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
{
    // Your code here
}
Run Code Online (Sandbox Code Playgroud)

  • 我们可以使用`<input type ="hidden"name ="randcheck"id ="randcheck"value ="<?php echo microtime();?>"/>` (3认同)
  • 我目前正在使用这种方法,带有令牌。但是,这会在多选项卡提交上产生问题。由于它将在每个选项卡上创建新的“rand()”,并覆盖会话值,这意味着打开的旧选项卡不再有效。有什么建议吗? (2认同)

Ibu*_*Ibu 12

处理表单后,您将重定向到另一个页面:

... process complete....
header('Location: thankyou.php');
Run Code Online (Sandbox Code Playgroud)

您也可以重定向到同一页面.

如果您正在执行类似注释的操作并且希望用户保持在同一页面上,则可以使用Ajax来处理表单提交


Mo'*_*med 12

我使用这个javascript行来阻止弹出窗口一旦提交表单就要求刷新表单重新提交.

if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}
Run Code Online (Sandbox Code Playgroud)

只需将此行放在文件的页脚上即可看到魔法


Pra*_*dra 11

  1. 使用标题并重定向页面.

    header("Location:your_page.php"); 您可以重定向到同一页面或不同页面.

  2. 将数据插入数据库后取消设置$ _POST.

    unset($_POST);

  • 取消设置$ _POST根本不会影响表单重新提交,至少不会影响Chrome. (48认同)
  • 不起作用。当用户返回页面时,它会再次执行 POST 变量的设置。 (2认同)

Eug*_*kov 8

我找到了下一个解决方法.您可以POST通过操作history对象来处理请求后转义重定向.

所以你有HTML表单:

<form method=POST action='/process.php'>
 <input type=submit value=OK>
</form>
Run Code Online (Sandbox Code Playgroud)

当您在服务器上处理此表单时,您可以/the/result/page通过设置Location标题来重定向用户,如下所示:

$cat process.php
<?php 
     process POST data here
     ... 
     header('Location: /the/result/page');
     exit();
?>
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在处理POSTed数据后,您渲染小<script>和结果/the/result/page

<?php 
     process POST data here
     render the <script>         // see below
     render `/the/result/page`   // OK
?>
Run Code Online (Sandbox Code Playgroud)

<script>您应该呈现:

<script>
    window.onload = function() {
        history.replaceState("", "", "/the/result/page");
    }
</script>
Run Code Online (Sandbox Code Playgroud)

结果是:

在此输入图像描述

正如您所见,表单数据被POST编辑为process.php脚本.
这个脚本程序POST编数据,并绘制/the/result/page一次有:

  1. 没有重定向
  2. POST刷新页面时没有重新数据(F5)
  3. POST通过浏览器历史记录导航到上一页/下一页时无法重复

UPD

作为另一种解决方案我问功能要求Mozilla Firefox的团队,以允许用户设置NextPage标头,会像Location头,使post/redirect/get模式已经过时.

简而言之.当服务器处理表单POST数据成功时:

  1. 设置NextPage标头而不是Location
  2. 渲染处理POST表单数据的结果,因为它将GETpost/redirect/get模式中呈现请求

浏览器依次看到NextPage标题:

  1. window.locationNextPage价值调整
  2. 当用户刷新页面时,浏览器将协商GET请求NextPage而不是重新POST形成数据

我认为如果实施这将是非常好的,不是吗? =)


小智 7

一个非常可靠的方法是在帖子中实现一个唯一的ID并将其缓存在

<input type='hidden' name='post_id' value='".createPassword(64)."'>
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中这样做:

if( ($_SESSION['post_id'] != $_POST['post_id']) )
{
    $_SESSION['post_id'] = $_POST['post_id'];
    //do post stuff
} else {
    //normal display
}

function createPassword($length)
{
    $chars = "abcdefghijkmnopqrstuvwxyz023456789";
    srand((double)microtime()*1000000);
    $i = 0;
    $pass = '' ;

    while ($i <= ($length - 1)) {
        $num = rand() % 33;
        $tmp = substr($chars, $num, 1);
        $pass = $pass . $tmp;
        $i++;
    }
    return $pass;
}
Run Code Online (Sandbox Code Playgroud)


Sev*_*ell 7

Javascript

这种方法非常简单,一旦提交表单,就会阻止在刷新时要求重新提交表单的弹出窗口。只需将这行 javascript 代码放在文件的页脚,就可以看到神奇之处。

<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>
Run Code Online (Sandbox Code Playgroud)