Post-redirect-get (PRG) reinserts the same page in history in Webkit browsers

Say I'm on / page? id = 1

Then I go to / page? id = 2

And am I making changes on this page that implements the message and then redirects back to / page? id = 2

In Firefox, can I click the "once" button once and return to / page? id = 1, but in Chrome and Safari on the iPhone I need to press the back button twice because / page? id = 2 is in the browser history twice. (And if I made several messages with id = 2, I would have to click the "Back" button to repeatedly return to id = 1.)

In a sense, this is similar to the normal behavior of the browser, as each GET is simply inserted into the history, but since the URL is identical to the previous record, this leads to a bad user experience, which is usually avoided by other web applications ... and, of course, you can Avoid in Firefox. Is this an unavoidable error in Webkit browsers, or can I implement PRG differently to avoid this?

btw- the behavior is similar to the same redirect from 302 or 303.

UPDATE: I was mocking some sample code ... I don't know if there is a platform like jsfiddle where I can download this for you to see in action:

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']); ?> 

Should I start with form.php? id = 4 (just to put it in your browser history) and then go to form.php? id = 5, and then click submit (as if to make a database change), in Firefox I get one history entry for each; in Chrome, I get one entry for id = 4, and then two entries for id = 5. Why is there a difference in behavior? I think Firefox's behavior is better, as striking twice back to get away from id = 5 is intuitive for the user.

+7
html google-chrome post-redirect-get mobile-safari webkit
source share
2 answers

Although this is not an explanation of what is happening, I have a way around this that I use in all my applications. First, some code:

form.php will look like this:

 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 as follows:

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

These are your documents with some additional material in the <form> tag and the new <script> .

I would also have an iframe somewhere in the document:

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

So to explain. Instead of moving to and from a new site every time you need to make changes, you simply load submit.php into an iframe into an existing document. Therefore, the target="iframe" .

Then, when the iframe , which means that the changes have been made, you reload the original page to reflect these changes, which means the window.parent.location.reload(); . Since the page just reloads, it will not add a second entry to your story.

Hope this helped you :)

+1
source share

We also faced the same problem, and even after several days of research, I did not find an “easy” solution. The closest I found is a Webkit Bugzilla ticket , which is apparently not a very high priority. As you already mentioned, IE and Firefox behave perfectly.

Since we have our own back button in the application, we were able to solve the problem using the session store and checking it when the page loads. TypeScript code is as follows:

 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, ""); } } 

We call DoubleHistoryWorkaround.saveLocation() when we press the back button, setting up session records that are checked by checkLocation() .

+1
source share

All Articles