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

60

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

请参见以下Chrome图片:

该对话框的文本为:

您正在查找的页面使用了您输入的信息。
返回该页面可能导致您采取的任何操作被重复执行。
您是否要继续?

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


我认为那就是浏览器的工作方式。我不确定你能做些什么。 - thescientist
可能是[如何在页面刷新(F5 / CTRL + R)时防止表单重新提交]的重复问题(https://dev59.com/Qm015IYBdhLWcg3w6QHA)。 - Eugen Konkov
9个回答

52
这种方法对我来说很有效,我认为最简单的方法是在重新加载的页面HTML中使用这个JavaScript代码。

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


2
但是有什么陷阱吗? - Akshay K Nair
我将这段代码放在<form>标签后面,当用户返回上一页时,它不会返回到前一页,而是返回到POST链中的前一个页面。 - David Spector

42

编辑:距离我最初发布这个答案已经过去了几年,虽然我得到了一些赞,但我并不满意以前的答案,所以我完全重做了它。希望这可以帮到你。


何时使用GETPOST

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

如果正在执行不希望重复的操作、传输敏感信息或者表单中包含文件上传或所有数据的长度超过2000个字符,则始终使用POST

需要使用POST的示例包括:

  • 登录表单
  • 联系表单
  • 提交付款表单
  • 向数据库添加、编辑或删除条目的内容
  • 图像上传器(请注意,如果使用具有<input type="file">字段的GET,则仅发送文件名到服务器,这在99.73%的情况下不是您想要的。)
  • 具有许多字段的表单(如果使用GET,则会创建一个很长的URL)
在任何这些情况下,您都不希望人们刷新页面并重新发送数据。如果您发送敏感信息,使用GET不仅不合适,而且还会引起安全问题(即使通过AJAX发送表单),因为敏感项(例如用户密码)会被发送到URL中,从而显示在服务器访问日志中。
基本上可以用GET来处理其他所有事情。这意味着当您不介意重复时,对于任何您可以提供直接链接的内容,当没有传输敏感信息时,当您相当确定您的URL长度不会失控并且您的表单没有任何文件上传时。
例子包括:
- 在搜索引擎中进行搜索 - 导航表单以在网站中导航 - 使用一次性密码或单次使用密码执行一次性操作(例如电子邮件中的"取消订阅"链接)。
在这些情况下,POST将是完全不合适的。想象一下如果搜索引擎使用POST进行搜索。每次刷新页面时,您都会收到此消息,并且您无法只复制并粘贴结果URL给其他人,他们必须手动填写表单。
如果您使用POST:
对我来说,大多数情况下,即使弹出“确认重新提交表单”对话框也显示存在设计缺陷。由于使用POST执行破坏性操作的本质,Web 设计师应该防止用户意外(或故意)刷新页面而再次执行它们。许多用户甚至不知道这个对话框的含义,因此只会单击“继续”。如果这是在“提交付款”请求之后呢?付款会再次发送吗?
那么你该怎么办呢?幸运的是,我们有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";
}

5
如果您使用GET并刷新页面,您将不会收到错误提示,但是数据将被重新提交。我不建议这样做。 - zatatatata
除非人们重复提交数据没有关系。 - Mike
1
很好的答案。它还强调了那些不改变服务器状态的表单提交应该使用“get”的事实。 - Rupert Rawnsley
3
如果服务端验证失败,你要如何重定向回相同的表单页面以展示无效值和错误消息?假设该表单有许多字段,无法在 cookie 中存储。同时,假设你不想使用服务器端状态。 - joshua
@DavidSpector,“error”是什么意思?您能详细解释一下您想要实现什么以及请求是如何发送的吗?如果正确实现,GET请求是幂等的,而POST请求则不是。这个问题特别涉及HTML表单,它没有其他幂等请求方法,比如HEAD、PUT、DELETE、OPTIONS或TRACE。 - Mike
显示剩余7条评论

11

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


1
如何使用重定向显示“成功注册”消息? - Martin Rose
对于重定向,在CI中如果您加载了url助手,您可以使用redirect('somecontroller/somefunction');作为简写。有关成功消息,请阅读用户指南中的flash会话部分。 - toopay
这个答案不适用于可以重复显示而不会造成伤害的表单。如何抑制重新提交错误消息? - David Spector

8
在处理POST页面后,将用户重定向到相同的页面。
http://test.com/test.php上。
header('Location: http://test.com/test.php');

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

1
这种方法的小缺陷是页面会在浏览器历史记录中出现两次。 - MrWhite
3
这难道不会最终导致无限重定向循环吗? - Matthew Oakley
@MatthewOakley 是的,即使有一个 exit; 也是如此。 - syfantid
这需要另一个检查,例如if($request present) {redirect},否则它将结束无限重定向循环... - mhk

3

看起来你正在寻找Post/Redirect/Get模式。

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

你可以立即处理和呈现处理结果,而无需POST确认警报。你只需要操作浏览器历史记录对象:

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

查看 完整 或者 简短 答案


翻译:没有解释清楚,你可以在这里提出模式建议。 - Dheeraj Thedijje

3
您可以尝试使用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();
?>

2

我曾遇到一种情况,无法使用以上任何答案。我的情况涉及与搜索页面的工作,如果用户在导航到任何搜索结果后单击返回,则会得到“确认表单重新提交”。我编写了以下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,它会打开该页面并删除被重定向页面的历史记录条目。 - Justin Liu

0

我找到了一种非正统的方法来完成这个。

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


-1

快速答案

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

例如。

Login.php

Login/index 加载登录表单

Login/validate 进行登录验证

登录成功

将用户重定向到 User/dashboard

登录失败

将用户重定向到 login/index


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