如何防止“确认表单重新提交”对话框?

Posted

技术标签:

【中文标题】如何防止“确认表单重新提交”对话框?【英文标题】:How to prevent the "Confirm Form Resubmission" dialog? 【发布时间】:2011-10-13 14:49:29 【问题描述】:

如何在提交后清除表单中的信息,使其在页面刷新后不显示此错误?

查看图片(来自 chrome):

对话框有文字:

您要查找的页面已使用 您输入的信息。回到那个 页面可能会导致您采取的任何操作 重复。要继续吗?

我不希望这个对话框出现。

【问题讨论】:

我认为这正是浏览器的工作方式。我不确定你能做些什么。 How to prevent form resubmission when page is refreshed (F5 / CTRL+R)的可能重复 【参考方案1】:

编辑:我最初发布这个答案已经有几年了,即使我得到了一些支持,但我对我之前的答案并不满意,所以我完全重做了.我希望这会有所帮助。


何时使用GETPOST

消除此错误消息的一种方法是让您的表单使用 GET 而不是 POST。请记住,这并不总是合适的解决方案(请阅读下文)。

如果您正在执行不想重复的操作、正在传输敏感信息或者您的表单包含文件上传或所有数据的长度,请始终使用 POST发送的时间长于~2000 characters。

何时使用POST 的示例包括:

登录表单 联系表格 提交付款表格 从数据库中添加、编辑或删除条目的东西 图片上传器(注意,如果使用带有<input type="file"> 字段的GET,则只会将文件名发送到服务器,这在99.73% 的情况下不是您想要的。) 一个包含许多字段的表单(如果使用 GET 会创建一个长 URL)

在任何这些情况下,您都不希望人们刷新页面并重新发送数据。如果您要发送敏感信息,使用 GET 不仅不合适,而且由于敏感项目(例如用户密码)是在URL,因此会显示在服务器访问日志中。

将 GET 用于其他任何事情。这意味着,当您不介意是否重复时,对于您可以提供直接链接的任何内容,当没有传输敏感信息时,当您非常确定您的 URL 长度不会失控并且当您的表单没有任何文件上传时。

示例包括:

在搜索引擎中执行搜索 用于浏览网站的导航表单 使用随机数或一次性密码执行一次性操作(例如电子邮件中的“取消订阅”链接)。

在这些情况下,POST 完全不合适。想象一下,如果搜索引擎使用 POST 进行搜索。每次刷新页面时,您都会收到此消息,并且您无法将结果 URL 复制并粘贴给人们,他们必须自己手动填写表单。

如果你使用POST:

对我来说,在大多数情况下,即使弹出“确认表单重新提交”对话框也表明存在设计缺陷。由于POST 被用于执行破坏性操作的本质,网页设计师应防止用户通过意外(或有意)刷新页面来多次执行它们。许多用户甚至不知道此对话框的含义,因此只会单击“继续”。如果那是在“提交付款”请求之后呢?是否会再次发送付款?

那你是做什么的?幸运的是,我们有Post/Redirect/Get 设计模式。用户向服务器提交 POST 请求,服务器将用户的浏览器重定向到另一个页面,然后使用 GET 检索该页面。

这是一个使用 php 的简单示例:

if(!empty($_POST['username'] && !empty($_POST['password'])) 
    $user = new User;
    $user->login($_POST['username'], $_POST['password']);

    if ($user->isLoggedIn()) 
        header("Location: /admin/welcome.php");
        exit;
    
    else 
        header("Location: /login.php?invalid_login");
    

请注意,在此示例中,即使密码不正确,我仍然会重定向回登录表单。要向用户显示无效的登录消息,只需执行以下操作:

if (isset($_GET['invalid_login'])) 
    echo "Your username and password combination is invalid";

【讨论】:

如果使用 GET 并刷新,则不会出现错误,但会重新提交数据。不推荐。 除非人们重新提交数据并不重要。 很好的答案。它还强调了不改变服务器状态的表单提交应该使用“get”。 如果服务器端验证失败,如何重定向回相同的表单,以便显示无效值和错误消息?假设表单有许多不适合 cookie 的字段。另外,假设您不想要服务器端状态。 @joshua 我不确定这是否会对您构成服务器端状态,但您可以将值存储在会话中以获取一个附加请求(即在重定向之后),然后将其删除.以 Laravel 的 flash() function 为例,了解如何实现这一点。如果这对您来说太有状态,请使用LocalStorage,因为大小限制比您可以放入 cookie 的数量级大几个数量级。【参考方案2】:

这个方法对我很有效,我认为最简单的方法是在重新加载页面的 html 中使用这个 javascript 代码。

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

【讨论】:

但是有什么问题呢?【参考方案3】:

这与您的表单或其中的值无关。它被浏览器触发,以防止用户对缓存数据重复相同的请求。如果您确实需要启用结果页面的刷新,您应该通过 PHP (header('Location:result.php');) 或您正在使用的其他服务器端语言重定向用户。元标记解决方案也应该可以禁用刷新时重新发送。

【讨论】:

如何通过重定向显示“注册成功”的消息? 对于重定向,在 CI 中如果你加载 url helper,你可以使用 redirect('somecontroller/somefunction'); 作为简写。有关成功消息,请阅读 flash session 部分的用户指南【参考方案4】:

我遇到了这个问题,added this JavaScript 在我的页面底部,它似乎有效。解决方案似乎要简单得多。有什么缺点吗?

<script>
if ( window.history.replaceState ) 
  window.history.replaceState( null, null, window.location.href );

</script>

【讨论】:

它非常适合我。我希望没有缺点。【参考方案5】:

处理完 POST 页面后,将用户重定向到同一页面。

开启 http://test.com/test.php

header('Location: http://test.com/test.php');

这将摆脱该框,因为刷新页面不会重新提交数据。

【讨论】:

这种方法的小警告是该页面会在浏览器历史记录中出现两次。 这不会导致无限循环的重定向吗? @MatthewOakley 确实如此。即使有出口; 这需要另一个检查,例如 if($request present) redirect 否则它将结束重定向的无限循环...【参考方案6】:

您似乎正在寻找Post/Redirect/Get 模式。

作为另一种解决方案,您可以完全停止使用重定向。

您可以在没有POST 确认警报的情况下一次处理并呈现处理结果。您应该只操作浏览器历史记录对象:

history.replaceState("", "", "/the/result/page")

查看full 或short 答案

【讨论】:

解释不正确,你可以在这里建议模式。【参考方案7】:

我遇到了无法使用上述任何答案的情况。我的案例涉及使用搜索页面,如果在导航到任何搜索结果后单击返回,用户将获得“确认表单重新提交”。我编写了以下 javascript 来解决这个问题。这不是一个很好的解决方案,因为它有点闪烁,并且不适用于 IE8 或更早版本。不过,尽管这对于处理此问题的人可能有用或有趣。

jQuery(document).ready(function () 

//feature test
if (!history)
    return;

var searchBox = jQuery("#searchfield");

    //This occurs when the user get here using the back button
if (history.state && history.state.searchTerm != null && history.state.searchTerm != "" && history.state.loaded != null && history.state.loaded == 0) 

    searchBox.val(history.state.searchTerm);

    //don't chain reloads
    history.replaceState( searchTerm: history.state.searchTerm, page: history.state.page, loaded: 1 , "", document.URL);

    //perform POST
    document.getElementById("myForm").submit();

    return;


    //This occurs the first time the user hits this page.
history.replaceState( searchTerm: searchBox.val(), page: pageNumber, loaded: 0 , "", document.URL);

);

【讨论】:

或者只使用window.location.replace它会打开该页面并删除它被重定向的页面上的历史条目。【参考方案8】:

您可以尝试在 jQuery 中使用 AJAX 调用。就像 youtube 如何在不刷新的情况下添加您的评论一样。这将消除刷新整体的问题。

您需要通过 ajax 调用发送必要的信息。 我将以 youtube 评论为例。

$.ajax(
    type: 'POST',
    url: 'ajax/comment-on-video.php',
    data: 
        comment: $('#idOfInputField').val();
     ,
    success: function(obj) 
        if(obj === 'true') 
            //Some code that recreates the inserted comment on the page.
        
    
);

您现在可以创建文件comment-on-video.php 并创建如下内容:

<?php
    session_start();

    if(isset($_POST['comment'])) 
        $comment = mysqli_real_escape_string($db, $_POST['comment']);
        //Given you are logged in and store the user id in the session.
        $user = $_SESSION['user_id'];

        $query = "INSERT INTO `comments` (`comment_text`, `user_id`) VALUES ($comment, $user);";
        $result = mysqli_query($db, $query);

        if($result) 
            echo true;
            exit();
        
    
    echo false;
    exit();
?>

【讨论】:

【参考方案9】:

我找到了一种非正统的方法来实现这一点。

只需将脚本页面放在 iframe 中即可。这样做可以刷新页面,即使在旧版浏览器上似乎也不会出现“确认表单重新提交”消息。

【讨论】:

【参考方案10】:

快速解答

使用不同的方法加载表单和保存/处理表单。

示例。

登录.php

Login/index 加载登录表单 验证登录 Login/validate

成功时

将用户重定向到User/dashboard

失败时

将用户重定向到login/index

【讨论】:

以上是关于如何防止“确认表单重新提交”对话框?的主要内容,如果未能解决你的问题,请参考以下文章

在我的 django 项目的 chrome 浏览器中按回“确认表单重新提交”

底部对话框打开时如何防止键盘关闭?

Django 表单需要重新提交

如何防止警报对话框被后退按钮关闭

如何防止 Jquery 对话框离开页面?

如何防止“请告诉 Microsoft 这个问题”对话框