post-redirect-get(PRG)将相同的页面重新插入到Webkit浏览器的历史记录中

时间:2016-07-14 21:53:36

标签: html google-chrome webkit mobile-safari post-redirect-get

让我们说/我在/ page?id = 1

然后我导航到/ page?id = 2

我在该页面上进行了更改,该页面实现了一个帖子,然后重定向回/ page?id = 2

在Firefox中,我可以点击后退按钮并返回/ page?id = 1,但在iPhone上的Chrome和Safari中,我必须按两次后退按钮,因为/ page?id = 2在浏览器中历史两次。 (如果我从id = 2发了多个帖子,我必须多次点击后退按钮才能最终返回id = 1.)

在某些方面,这似乎是正常的浏览器行为,因为每个GET都被简单地推送到历史记录中,但由于URL与前一个条目相同,这会导致糟糕的用户体验,这通常似乎可以避免其他Web应用程序......在Firefox中自然可以避免。 这是Webkit浏览器中不可避免的错误,还是我可以用不同的方式实现PRG以避免这种情况?

btw-行为似乎与302或303重定向相同。

更新:我已经嘲笑了一些示例代码...不知道是否有像jsfiddle这样的平台我可以上传这个以供您查看动作:

form.php的:

id=<?=$_REQUEST['id']?>
<form action="submit.php" method="post">
<input type="hidden" name="id" value="<?=$_REQUEST['id']?>">
<input type="submit" value="submit">
</form>

submit.php:

<?php
header("Location: form.php?id=" . $_REQUEST['id']);
die($_REQUEST['id']);
?>

如果我从form.php开始?id = 4(只是将它放在浏览器历史记录中)然后转到form.php?id = 5然后点击提交(好像要执行数据库更改), Firefox我在每个历史记录中都有一个条目;在Chrome中,我得到一个id = 4的条目,然后是id = 5的两个条目。为什么行为不同?我认为Firefox的行为更好,因为回击两次以远离id = 5对用户来说是违反直觉的。

2 个答案:

答案 0 :(得分:1)

虽然这不是对发生的事情的解释,但我可以在我的所有应用程序中使用它。首先是一些代码:

form.php看起来像这样:

id=<?=$_REQUEST['id']?>
<form action="submit.php" target="iframe" method="post">
    <input type="hidden" name="id" value="<?=$_REQUEST['id']?>">
    <input type="submit" value="submit">
</form>
像这样的

submit.php

<?php
    header("Location: form.php?id=" . $_REQUEST['id']);
    die($_REQUEST['id']);
?
<script>
    window.parent.location.reload();
</script>

这是您的文档,其中包含<form>标记中的一些额外内容以及全新的<script>代码

我在文档中的某个地方也会有iframe,如下所示:

<iframe name="iframe"></iframe>

所以解释一下。您只需在现有文档中的submit.php中加载iframe,而无需导航到新网站并在每次需要进行更改时再次返回。因此target="iframe"部分。

然后当iframe已加载,意味着已进行更改时,您重新加载原始页面以反映这些更改,因此window.parent.location.reload();部分。由于页面只是重新加载,因此不会在历史记录中添加第二个条目。

我希望这有助于你:)

答案 1 :(得分:1)

我们也遇到了同样的问题,甚至经过几天的研究,我发现没有“简单”的解决方案。我发现的最接近的是这个Webkit Bugzilla ticket,从它的外观来看似乎不是非常高的优先级。正如你所提到的,IE和Firefox表现得很好。

由于我们在应用程序中有自己的后退按钮,因此我们能够通过使用会话存储并在加载页面时进行检查来解决问题。 TypeScript代码如下:

class DoubleHistoryWorkaround {

    // key of the attribute we store the URL we where on when clicking on the back button
    private static comingFromLabel = "comingFromURL";
    // key of the attribute of the flag denoting whether we set a valid comingFromURL
    private static comingFromFlag = "comingFromSet";

    constructor() {
        this.checkLocation();
    }

    /**
     * Checks the URL we saved in the session and goes a further step back
     * in the history if the first back button brought us to the same page again.
     */
    private checkLocation() {
        let doubleEntry : boolean;
        // have we set a comingFromURL?
        let comingFromSet = window.sessionStorage.getItem(DoubleHistoryWorkaround.comingFromFlag);
        if (comingFromSet) {

            // is the set comingFromURL the same as our current page?
            let currentURL = window.location.href;
            let comingFromURL = window.sessionStorage.getItem(DoubleHistoryWorkaround.comingFromLabel);
            if (currentURL === comingFromURL) {
                // double history entry detected
                doubleEntry = true;

                // before we skip we save our location ourselves, since we might still navigate
                // to the same page again (in case of triple identical history entries)
                DoubleHistoryWorkaround.saveLocation();

                // skip this page
                history.back();
            }
        }

        // reset the location entry unless we just set it ourselves
        if (!doubleEntry) {
            this.resetLocation();
        }
    }

    /**
     * Saves the current location in the session storage.
     */
    public static saveLocation() {
        window.sessionStorage.setItem(DoubleHistoryWorkaround.comingFromFlag, "true");
        window.sessionStorage.setItem(DoubleHistoryWorkaround.comingFromLabel, window.location.href);
    }

    /**
     * Removes the set location from the session storage.
     */
    private resetLocation() {
        window.sessionStorage.setItem(DoubleHistoryWorkaround.comingFromFlag, "false");
        window.sessionStorage.setItem(DoubleHistoryWorkaround.comingFromLabel, "");
    }
}

当我们点击应用程序的后退按钮,设置DoubleHistoryWorkaround.saveLocation()检查的会话条目时,我们会调用checkLocation()