58

How do I clean information in a form after submit so that it does not show this error after a page refresh?

See image (from chrome):

The dialog has the text:

The page that you're looking for used
information that you entered. Returning to that
page might cause any action you took to be
repeated. Do you want to continue?

I want this dialog not to appear.

MrWhite
  • 43,179
  • 8
  • 60
  • 84
Martin Rose
  • 599
  • 1
  • 4
  • 6
  • I think that's just the way the browser will work. I'm not sure there's anything you can do about it. – thescientist Jul 26 '11 at 17:17
  • Possible duplicate of [How to prevent form resubmission when page is refreshed (F5 / CTRL+R)](https://stackoverflow.com/questions/6320113/how-to-prevent-form-resubmission-when-page-is-refreshed-f5-ctrlr) – Eugen Konkov Nov 12 '17 at 11:44

9 Answers9

51

This method works for me well and I think the simplest way to do this is to use this javascript code inside the reloaded page's HTML.

if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}
Justin Liu
  • 581
  • 6
  • 21
Tanmoy Datta
  • 1,604
  • 1
  • 17
  • 15
42

Edit: It's been a few years since I originally posted this answer, and even though I got a few upvotes, I'm not really happy with my previous answer, so I have redone it completely. I hope this helps.


When to use GET and POST:

One way to get rid of this error message is to make your form use GET instead of POST. Just keep in mind that this is not always an appropriate solution (read below).

Always use POST if you are performing an action that you don't want to be repeated, if sensitive information is being transferred or if your form contains either a file upload or the length of all data sent is longer than ~2000 characters.

Examples of when to use POST would include:

  • A login form
  • A contact form
  • A submit payment form
  • Something that adds, edits or deletes entries from a database
  • An image uploader (note, if using GET with an <input type="file"> field, only the filename will be sent to the server, which 99.73% of the time is not what you want.)
  • A form with many fields (which would create a long URL if using GET)

In any of these cases, you don't want people refreshing the page and re-sending the data. If you are sending sensitive information, using GET would not only be inappropriate, it would be a security issue (even if the form is sent by AJAX) since the sensitive item (e.g. user's password) is sent in the URL and will therefore show up in server access logs.

Use GET for basically anything else. This means, when you don't mind if it is repeated, for anything that you could provide a direct link to, when no sensitive information is being transferred, when you are pretty sure your URL lengths are not going to get out of control and when your forms don't have any file uploads.

Examples would include:

  • Performing a search in a search engine
  • A navigation form for navigating around the website
  • Performing one-time actions using a nonce or single use password (such as an "unsubscribe" link in an email).

In these cases POST would be completely inappropriate. Imagine if search engines used POST for their searches. You would receive this message every time you refreshed the page and you wouldn't be able to just copy and paste the results URL to people, they would have to manually fill out the form themselves.

If you use POST:

To me, in most cases even having the "Confirm form resubmission" dialog pop up shows that there is a design flaw. By the very nature of POST being used to perform destructive actions, web designers should prevent users from ever performing them more than once by accidentally (or intentionally) refreshing the page. Many users do not even know what this dialog means and will therefore just click on "Continue". What if that was after a "submit payment" request? Does the payment get sent again?

So what do you do? Fortunately we have the Post/Redirect/Get design pattern. The user submits a POST request to the server, the server redirects the user's browser to another page and that page is then retrieved using GET.

Here is a simple example using 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");
    }
}

Notice how in this example even when the password is incorrect, I am still redirecting back to the login form. To display an invalid login message to the user, just do something like:

if (isset($_GET['invalid_login'])) {
    echo "Your username and password combination is invalid";
}
Community
  • 1
  • 1
Mike
  • 23,542
  • 14
  • 76
  • 87
  • 5
    If you use GET and refresh, you don't get the error, but data is resubmitted. Wouldn't recommend it. – zatatatata Jul 26 '11 at 18:32
  • Unless it doesn't matter if people resubmit the data. – Mike Jul 26 '11 at 20:30
  • 1
    Great answer. It also emphasises the fact that form submissions that do not change the server state should use "get". – Rupert Rawnsley Jan 06 '16 at 09:18
  • 3
    If serverside validation fails, how do you redirect back to the same form so that you can display the invalid values and error messages? Assume the form has many fields that wont fit in a cookie. Also, assume you don't want serverside state. – joshua Nov 28 '18 at 12:38
  • @joshua I'm not sure if this would constitute server-side state to you, but you could store the values in the session for one single additional request (i.e. after the redirect) and then delete it. Take a look at Laravel's [`flash()` function](https://laravel.com/docs/5.7/session#flash-data) as an example of how this can be achieved. If that is too stateful for you, use `LocalStorage` since the size limits are orders of magnitude larger than what you can put in a cookie. – Mike Nov 28 '18 at 17:11
  • Nice, header-location is the answer! As it doesn't create an instance in history that would prompt you to resend while using the Back button for example. – Fanky Jan 31 '19 at 13:00
  • The answer only handles the case of one-time-only forms. What about forms that are idempotent (they can be repeated)? Then what does the programmer do to allow the form to be resubmitted without error? – David Spector Jul 17 '22 at 11:10
  • @DavidSpector What do you mean by "error"? Can you explain a bit more about what you're trying to accomplish and how the request is being sent? If implemented correctly, GET requests are idempotent and POST requests are not idempotent. This question is specifically about HTML forms, which do not have other idempotent request methods such as HEAD, PUT, DELETE, OPTIONS or TRACE. – Mike Jul 18 '22 at 04:05
  • I used "error" to mean the warning to the user about resubmitting data. In the case of my forms, there is no problem resubmitting. My use case is a series of forms shown to the user to navigate a UI. I don't want to use GET because I don't want the user to see sensitive data or to save the inner URLs as a means to skip earlier forms. So I want the simplicity of `no query` in the address bar provided by POST without the warning message. I think this is impossible without resorting to `target=_blank` so there is a separate tab or window created in the browser.. – David Spector Jul 19 '22 at 09:34
  • One solution would be to use JavaScript and Ajax to obtain the data from a POST form at submission time, and put it into a session variable, using JavaScript when done instead of POST submit. That way the data is captured, but the form can be resubmitted, and the address bar either changed not changed by JavaScript. – David Spector Jul 19 '22 at 09:48
  • @DavidSpector I guess it depends on your definition of "sensitive". Anything that goes into `GET` will likely be logged by the server in plain text. If this needs to be encrypted, then you can't use `GET`. If it doesn't matter that it's logged in plain text, then you can probably use it. – Mike Jul 19 '22 at 17:19
  • Assuming the information is not actually truly "sensitive" in nature, it seems to me like you could do what you are trying to do by using a CSRF token to prevent them from sharing the URL, and by simply storing the step they are on in the form in their session. That way if the session says they're on step 2 and they alter the URL and put in step 5, you can block the request. – Mike Jul 19 '22 at 17:23
11

It has nothing to do with your form or the values in it. It gets fired by the browser to prevent the user from repeating the same request with the cached data. If you really need to enable the refreshing of the result page, you should redirect the user, either via PHP (header('Location:result.php');) or other server-side language you're using. Meta tag solution should work also to disable the resending on refresh.

Chin
  • 19,717
  • 37
  • 107
  • 164
zatatatata
  • 4,761
  • 1
  • 20
  • 41
  • 1
    How with redirects, i display messages 'registered successfully'? – Martin Rose Jul 26 '11 at 17:29
  • For redirect, in CI if you load url helper, you can use `redirect('somecontroller/somefunction');` as shorthand. For success message, read the userguide at flash session section – toopay Jul 26 '11 at 18:21
  • This answer doesn't work with forms that can be shown repeatedly without harm. How to suppress the resubmission error message? – David Spector Jul 17 '22 at 11:13
8

After processing the POST page, redirect the user to the same page.

On http://test.com/test.php

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

This will get rid of the box, as refreshing the page will not resubmit the data.

3

It seems you are looking for the Post/Redirect/Get pattern.

As another solution you may stop to use redirecting at all.

You may process and render the processing result at once with no POST confirmation alert. You should just manipulate the browser history object:

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

See full or short answers

Eugen Konkov
  • 22,193
  • 17
  • 108
  • 158
3

You could try using AJAX calls with jQuery. Like how youtube adds your comment without refreshing. This would remove the problem with refreshing overal.

You'd need to send the info necessary trough the ajax call.
I'll use the youtube comment as example.

$.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.
        }
    }
});

You can now create the file comment-on-video.php and create something like this:

<?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();
?>
Kerwin Sneijders
  • 750
  • 13
  • 33
2

I had a situation where I could not use any of the above answers. My case involved working with search page where users would get "confirm form resubmission" if the clicked back after navigating to any of the search results. I wrote the following javascript which worked around the issue. It isn't a great fix as it is a bit blinky, and it doesn't work on IE8 or earlier. Still, though this might be useful or interesting for someone dealing with this issue.

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);

});
Felix Steiny
  • 191
  • 1
  • 2
  • Or just use `window.location.replace` it opens that page and also deletes the history entry on the page it was redirected from. – Justin Liu May 28 '20 at 18:05
0

I found an unorthodox way to accomplish this.

Just put the script page in an iframe. Doing so allows the page to be refreshed, seemingly even on older browsers without the "confirm form resubmission" message ever appearing.

Joe
  • 143
  • 10
-1

Quick Answer

Use different methods to load the form and save/process form.

Example.

Login.php

Load login form at Login/index Validate login at Login/validate

On Success

Redirect the user to User/dashboard

On failure

Redirect the user to login/index

Dheeraj Thedijje
  • 1,053
  • 12
  • 19