26

I am doing web development.

I have a page to do with credit card, which when user click "refresh" or "Back", the transaction will be performed one more time, which is unwanted.

This include Browser top left "Back" & "Refresh" button, "right click->Refresh/Back", press "F5" key. This is to be done on certain cgi page only, not all of them.

Can this be done using Javascript? Or any other method?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

13 Answers13

50

The standard way is to do it in 3 steps.

  1. the form page submits fields to processing page
  2. processing page processes data and redirects to result page
  3. result page just displays results, reloading it won't do any harm.
Hank Gay
  • 70,339
  • 36
  • 160
  • 222
vartec
  • 131,205
  • 36
  • 218
  • 244
  • 16
    Also known as the Post-Redirect-Get pattern. – Rob May 08 '09 at 01:46
  • 27
    This doesn't stop the form from being reprocessed if the user hits "Back" (if they tell their browser to resubmit) – philfreo Oct 29 '09 at 21:48
  • 4
    @philfreo- actually, it does prevent it. Most frameworks today will issue a "302 Moved" header, which effectively tells the browser to use the results page for the history during back-button navigation. – George Armhold Oct 05 '12 at 11:42
  • 1
    What about in Single Page Applications, where somebody posted to your app ? – jamiebarrow Oct 02 '13 at 10:52
  • 1
    @jamiebarrow: in SPA you'd use AJAX calls to submit forms. – vartec Oct 02 '13 at 11:56
  • @vartec You're misunderstanding me, I mean if someone else does a form post to the SPA. For example, a separate payment gateway system that you don't have control over. Asked question here - http://stackoverflow.com/questions/19135515/avoiding-form-resubmission-in-spa-without-p-r-g – jamiebarrow Oct 02 '13 at 14:16
  • 1
    If you use a HTTP POST to submit the transaction most browsers warn you that you will be resubmitting the form when you press the back button. It helps prevent the user pressing the back button somewhat. http://stackoverflow.com/questions/16091067/why-does-the-back-button-not-work-with-http-post – Matthew Lock Sep 08 '14 at 03:58
  • is there any way if I can tell whether a page is implemented like this? The page I am looking at showed a warning about clicking "Back" but not refresh. That would fit with this answer... But when I tried refresh, my browser warned me "The page that you're looking for used information that you entered. Returning to that page might cause any action that you took to be repeated. Do you want to continue?" – craq Aug 22 '20 at 09:20
12

This breaks the basic browser user experience model...users should always be able to use the Refresh and Back buttons in their browser. Recommend that you fix your page another way.

If you update your question to include the server language/platform/technology that you are using then someone might be able to suggest a solution.

Richard Ev
  • 52,939
  • 59
  • 191
  • 278
9

The simple fact that resubmitting the form generates a duplicate transaction is worrying. You should have some sort of check to ensure each submit of form data is unique.

For example, the page which would submit the form should be given a unique ID that gets submitted with the form. The business logic should then be able to recognise that the form submitted has already been processed (as the (no longer) unique ID will be the same), so ignores the second attempt.

The 'standard way' still doesn't stop clients from clicking the back button twice... or even going back and resubmitting the form if they don't think (for whatever reason) it has been processed.

James Camfield
  • 1,636
  • 3
  • 16
  • 24
7
  1. generate a random string and store it in session,

  2. then output it to your form as a hidden value,

  3. check the submitted and store variable, if matches process your request,

  4. go to 1.

Anonymous
  • 4,692
  • 8
  • 61
  • 91
3

Place this code on the form page

Response.Cache.SetCacheability(HttpCacheability.NoCache);

Response.Cache.SetExpires(DateTime.Now-new TimeSpan(1,0,0));

Response.Cache.SetLastModified(DateTime.Now);

Response.Cache.SetAllowResponseInBrowserHistory(false);
Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
  • What is this code supposed to do ? Expire the page when user hits back button ? – vsingh Mar 26 '10 at 15:42
  • 3
    +1 That is c# code that will make the browser give a "Page Expired" warning if a user tries to click "Back" on their browser – Jimbo Dec 02 '10 at 07:13
2

You shouldn't try to "block" these actions. What you should do is make sure that nothing happends when someone "double submits" the form.

andi
  • 14,322
  • 9
  • 47
  • 46
1

I didn't see this here so here it is.

  1. Put a unique token in the form.
  2. The submit button triggers an xmlhttp(ajax) request to the server to create a session variable named after the token with a stored value of 1.
  3. The ajax request submits the form after receiving a positive state change.
  4. The form processing script checks for the session variable withe the stored value of 1.
  5. The script removes the session variable and processes the form.

If the session variable is not found, the form will not be processed. Since the variable is removed as soon as its found, the form can only be run by pressing the submit button. Refresh and back will not submit the form. This will work without the use of a redirect.

1

and in some browser you can´t even do that, and this is good!

Tobias
  • 7,238
  • 10
  • 46
  • 77
1

The best way is to have enough session handling logic that you can recognise the 2nd (and onwards) attempt as "this is just a re-submission" and ignore it.

Vatine
  • 20,782
  • 4
  • 54
  • 70
0

I found the above Post/Redirect/Get explanations a little ambiguous

Here's what I followed and hopefully it helps someone in the future

http://wordsideasandthings.blogspot.ca/2013/04/post-redirect-get-pattern-in-php.html

Essentially the process based on the above solution is:

  1. Submit from the FORM page to the processing page (or to itself)
  2. Handle database or payment processing etc
  3. If required, store user feedback message in a session variable, possible error messages etc
  4. Perform header redirect to results page (or to original form page). If required, display custom message from processing page. Such as "Error Credit Card payment was rejected", and reset session variables.

Redirect with something like:

header("HTTP/1.1 303 See Other");
header("Location: http://$_SERVER[HTTP_HOST]/yourfilehere.php");
die();

The header redirect will initiate a GET request on "yourfilehere.php", because a redirect is simply that, a "request" to fetch data FROM the server, NOT a POST which submits data TO the server. Thus, the redirect/GET prevents any further DB/payments processing occurring after a refresh. The 301 error status will help with back button pressing.

Helpful Reading:

  1. http://en.wikipedia.org/wiki/URL_redirection#HTTP_status_codes_3xx
  2. http://www.theserverside.com/news/1365146/Redirect-After-Post
  3. http://wordsideasandthings.blogspot.ca/2013/04/post-redirect-get-pattern-in-php.html
  4. https://en.wikipedia.org/wiki/HTTP#Request_methods
  5. http://en.wikipedia.org/wiki/Post/Redirect/Get
wired00
  • 13,930
  • 7
  • 70
  • 73
0

Just put this javascript on the html section of aspx page above head section

<script type = "text/javascript" >
function disableBackButton()
{
window.history.forward();
}
setTimeout("disableBackButton()", 0);
</script>

We need to put it on the html section of the page which we want to prevent user to visit by hitting the back button

Complete code of the page looks like this

<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<script type = "text/javascript" >
function disableBackButton()
{
window.history.forward();
}
setTimeout("disableBackButton()", 0);
</script>
</head>
<body onload="disableBackButton()">
<form id="form1" runat="server">
<div>
This is First page <br />
<br />
Go to Second page
<br />
<br />
<asp:LinkButton ID="LinkButton1" runat="server"
PostBackUrl="~/Default2.aspx">Go to Second Page
</asp:LinkButton></div>
</form>
</body>
</html>

If you are using firefox then use instead of onload

If you want to disable back button using code behind of aspx page,than you need to write below mentioned code C# code behind

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string strDisAbleBackButton;
strDisAbleBackButton = "<script language="javascript">\n";
strDisAbleBackButton += "window.history.forward(1);\n";
strDisAbleBackButton += "\n</script>";
ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "clientScript", strDisAbleBackButton);
} 

We can also achieve this by disabling browser caching or cache by writing this line of code either in Page_load event or in Page_Init event

protected void Page_Init(object Sender, EventArgs e)
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
Response.Cache.SetNoStore();
}

Doing this,user will get the page has expired message when hitting back button of browser

Demo is :

enter image description here

Ramesh Rajendran
  • 37,412
  • 45
  • 153
  • 234
0

This code works for not back from current page me..

Here I put a code which helps you , not open contextmenu and on browser reload ask you leave a page or not...

I am trying the ask click on browser back button

jQuery( document ).ready(function() {

    document.onkeydown = fkey;
    document.onkeypress = fkey
    document.onkeyup = fkey;

    var wasPressed = false;

    function fkey(e){
        e = e || window.event;
        //alert(e.keyCode);
        if( wasPressed ) return; 


        if (e.keyCode == 116 || e.keyCode == 8 || e.keyCode == 17) {
                     // alert("f5 pressed");
                      window.onbeforeunload = null;
                      return true;
                 }

    }
window.onbeforeunload = function (event) {
    var message = ''; // Type message here

    if (typeof event == 'undefined') {
        event = window.event;
    }
    if (event) {
        event.returnValue = message;
    }

    return message;
};

jQuery(function () {

    jQuery("a").click(function () {
        window.onbeforeunload = null;
    });

    jQuery(".btn").click(function () {
        window.onbeforeunload = null;
    });

    //Disable part of page
    $(document).on("contextmenu",function(e){
        return false;
    });
});});

Thanks,

Bhavin Patel
  • 133
  • 11
0

vartec:s solution solves the reload-problem, not the back-problem, so here are a solution to that:

  1. The form page sets a session variable, for example session("fromformpage")=1
  2. The processing page check the session variable, if its ="1" then process data and redirect to result page if any other than ="1" then just redirect to result page.
  3. The result page sets the session variable to "".

Then if the user is pressing back button, the processing page will not do the process again, only redirect to process page.

Stefan
  • 11,423
  • 8
  • 50
  • 75