?
Solved

Avoiding save record while refresh after submit

Posted on 2003-03-27
21
Medium Priority
?
850 Views
Last Modified: 2008-02-01
While I am submitting a form to save record in the database, if I press F5 or click button refresh in the browser it will get submitted twice and record getting inserted twice. How can I avoid this problem?
0
Comment
Question by:shankarvel
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 5
  • 3
  • +3
21 Comments
 
LVL 10

Accepted Solution

by:
MaxOvrdrv2 earned 1000 total points
ID: 8218529
set a session variable when you record the information:

if Session("Saved")=0 then
   rs.fields("whatever")=whatever
   rs.update
   Session("Saved")=1
   response.write "Record Saved"
else
   response.write "Record Saved
end if

and then upon loading the page with the form, set the session to 0, that way... only if the page with the form is loaded and submitted will it be saved in the DB...

MaxOvrdrv2
0
 
LVL 18

Expert Comment

by:mgfranz
ID: 8218532
You need to clear the browser cache for that page;

You start with META tags in the HEAD of the page.
Not well supported by some browsers.

The first instructs no caching:
<meta HTTP-EQUIV="Pragma" CONTENT="no-cache">

The second is necessary because IE5 ignores the pragma:

<META HTTP-EQUIV="Expires" CONTENT="-1">
That expires the page as soon as it is born.

However that may still not work in IE because it it is in the head where it has to be.  In some kind of twisted logic IE sees the META tags, but because the page has not yet been loaded there is nothing to cache so it ignores it. Then when the page is loaded, it caches it.  The solution from Microsoft is to duplicate the tags after the end of the body.  However they have to be in the head so you end up with this silly looking, but effective page setup:

<HTML>
<HEAD>
<TITLE>---</TITLE>
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">

all the other head stuff

</HEAD>
<BODY>

All the good stuff that makes the page worthwhile

</BODY>
<HEAD>
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">
</HEAD>
</HTML>



For ASP if you  want the same non-cache effect, here's the header
information:
<% Response.CacheControl = "no-cache" %>>
<% Response.AddHeader "Pragma", "no-cache" %>
<% Response.Expires = -1 %>

I don't know if once does it for ASP or if you have to repeat
that as well.


And of course Netscape always has to add a twist of its own.  Pages
with forms in Netscape can be a problem especially for secure environments.

Netscape suggests the following JavaScript be used in the BODY tag
of all pages that should not be cached:
<body onLoad="if ('Navigator' == navigator.appName) document.forms[0].reset();"

0
 
LVL 18

Expert Comment

by:mgfranz
ID: 8218564
Using Session is a good idea, however it doesn't prevent the user from coming back and doinng a submit later...  Cookies are an option that can prevent the user from ever getting the form page again, but it has faults too.

One way to ensure you don't get duplicate records is to simple check the contents of the dB against what is being passed for duplicates, if so, then redirect.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 46

Expert Comment

by:fritz_the_blank
ID: 8218580
Here is a simple approach. On the form that has the data to be submitted, do this:

<body onLoad="history.forward()">

If there is no relevant page nothing will happen. However, if someone hits the back button, it will push them back to where they were without resubmitting the form.

Fritz the Blank
0
 
LVL 46

Expert Comment

by:fritz_the_blank
ID: 8218593
I should say that I usually do exactly what MGFranz suggests, but what I posted above is a good suplement.

Fritz the Blank
0
 
LVL 10

Expert Comment

by:MaxOvrdrv2
ID: 8218795
mq... if you clear the cache... and refresh... won<t that cause an ADODB error?? since there is no information to select from, he would then have to account for that?

MaxOvrdrv2
0
 
LVL 18

Expert Comment

by:mgfranz
ID: 8218845
Yes, which is why you should always do some simple checks on the page, or build in the redirect if the var is empty.  

It's really simple, do the client-side form validation on the form page, if the form is populated correctly, pass the values to the processing page, if the vars are empty on the processing page, redirect to the form page, if not process the records then redirect to the next viewable page.  The processing page is never kept in the buffer.
0
 
LVL 10

Expert Comment

by:MaxOvrdrv2
ID: 8218916
yeah... that's what i thought... i just wanted to clarify... ;-)

thanks!

MaxOvrdrv2
0
 
LVL 10

Expert Comment

by:apollois
ID: 8218917
Hi shankarvel,

<%

'--- PREVENT PAGE FROM BEING CACHED ---
'     Put this at the top of your ASP code
'     This code is based on a number of KB articles

Response.Expires               = -100000
Response.Expiresabsolute     = Now() - 2
Response.AddHeader               "pragma","no-cache"
Response.AddHeader               "cache-control","private"
Response.CacheControl          = "no-cache"
%>


REFERENCES:

Cache No More by Phil Paxton
http://www.learnasp.com/learn/cachenomore.asp

Preventing users from re-submitting a form.
http://www.devguru.com/features/knowledge_base/A100220.asp


Best Regards,
>apollois<
0
 
LVL 18

Expert Comment

by:mgfranz
ID: 8218952
apollois, I believe I already said that...
0
 
LVL 10

Expert Comment

by:apollois
ID: 8218979
mgfranz,

If you check your response statements you will find they are different from mine.

Plus I gave shankarvel some detailed references to further educate him/her.

Best Regards,
>apollois<
0
 
LVL 18

Expert Comment

by:mgfranz
ID: 8219024
The headers will return exactly the same response with my code as yours.

Yes references are good...
0
 
LVL 10

Expert Comment

by:apollois
ID: 8219157
mgfranz,

>>> The headers will return exactly the same response with my code as yours. <<<

I'm sorry, I have to disagree.

Your code:
~~~~~~~~~~~~~~~~~~~~BeginQuote~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<% Response.CacheControl = "no-cache" %>>
<% Response.AddHeader "Pragma", "no-cache" %>
<% Response.Expires = -1 %>
~~~~~~~~~~~~~~~~~~~~~EndQuote~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

There are numerous Microsoft and other articles stating that the Response.Expires = -1 does not always yield expected results.  The recommended settings are:

Response.Expires               = -100000
Response.Expiresabsolute     = Now() - 2

Plus you do NOT have the following:

Response.AddHeader               "cache-control","private"


The code I posted is based on considerable research and testing I did on this subject some time ago.  This code maximizes the probability that the page will NOT be cached.  This is a difficult problem to overcome reliably.  I'm simply offering the best help I can.

Why are you so worried about my post?  It is significantly different from yours. I'm sure that shankarvel can make a good decision.  If your post satisfies his/her needs, then he/she should select your comment as answer.  If not, and mine does, then he/she can select my comment.  Are you that worried about the points? If you have any further concerns, please email me (address is in my profile) so that this question is not further polluted.


Best Regards,
>apollois<
0
 
LVL 18

Expert Comment

by:mgfranz
ID: 8219283
'Response.CacheControl="private" ' HTTP 1.1 Cache-Control header : prevent the caching at the proxy server only.

This is a waste of resources and not necessary;
Response.Expires               = -100000
Response.Expiresabsolute     = Now() - 2

.Expires is going to be called whethe rits -1 or -100000

Heres all the rules;

<%'-- PAGES CACHING CONTROL --
  '-- Use the following script at the extreme beginning of the specific ASP pages

'-- Prevent caching at the proxy server
Response.CacheControl = "no-store" ' HTTP 1.1 Cache-Control header : prevent all caching of a particular Web resource
'Response.CacheControl = "no-cache" ' HTTP 1.1 Cache-Control header : prevent all caching of a particular Web resource
'Response.CacheControl="private" ' HTTP 1.1 Cache-Control header : prevent the caching at the proxy server
'' Response.CacheControl="public"     ' HTTP 1.1 Cache-Control header : enable caching at the proxy server

' Prevent clients from caching web pages :
' no-cache prevents caching only when used over a secure (https://) connection.
' Treated identically to Expires: -1 if used in a non-secure page.
Response.AddHeader "Pragma", "no-cache" ' (META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE")
'Response.AddHeader "cache-control", "no-store"
' Note the Web page may still be cached in the Temporary Internet Files folder.
' see http://support.microsoft.com/support/kb/articles/Q222/0/64.ASP for reasons & resolutions
 
'-- Set page expiration date
Response.Expires = -1 ' cached but marked as immediately expired. (META HTTP-EQUIV="Expires" CONTENT="-1")
''Response.ExpiresAbsolute = Now() -1
' However, the page remains in the disk cache ("Temporary Internet Files") and is used in appropriate situations
' without contacting the remote Web server, such as when the BACK and FORWARD buttons are used to access the navigation history
%>

0
 
LVL 18

Expert Comment

by:mgfranz
ID: 8219295
Oh yeah, I have no problem with your post, or your suggestions, they just seemed redundant thats all.

0
 
LVL 10

Expert Comment

by:apollois
ID: 8219440
mgfranz,

>>> .Expires is going to be called whethe rits -1 or -100000 <<<

Maybe, maybe not.  I understand that's what the basic documentation says.  But I have read Microsoft articles that say -1 is not reliable, and recommend using the -100000 value.

I can say this much for sure.  Using my code does no harm.  It will do at least as good a job as your code, and it may provide additional help in preventing caching.  So there is really no reason not to use it.

I thoroughly researched and tested my posted code.  I'll stand with my original post.

Best Regards,
>apollois<
0
 
LVL 18

Expert Comment

by:mgfranz
ID: 8219498
I have never seen those articles...  I never said your example wouldn't work, I just said it seemed reduntant to my post.  I know my methods work as well.  What needs to be remembered is that there are other functions and methods that need to be worked with as well as cache, page cache is only part of the picture.
0
 
LVL 4

Expert Comment

by:anderson22
ID: 8221236
Best thing to do after an insert is to execute a response.redirect to the same page.  Even if you hit F5 it will just repost the last headers which execute a GET request.  Assuming you can do this and display the page properly.

Similar situation:
http://www.experts-exchange.com/Web/Q_20562245.html

-rca
0
 
LVL 46

Expert Comment

by:fritz_the_blank
ID: 8319736
Were any of these comments helpful? If so, please select one as an answer to close out the question.

Fritz the Blank
0
 
LVL 10

Expert Comment

by:apollois
ID: 8335095
shankarvel,

OK, after having to deal with this same problem myself, I have developed a solid solution to prevent resaving of the data to the DB.  The only weakness in this solution is that it requires the user to have enabled javascript.

===================================================
HOW TO PREVENT RESUBMIT OF FORM DATA BY REFRESH
===================================================

THE PROBLEM:
The user submits a form, and receives a comfirmation page.  The user refreshes the confirmation page causing the same data to be processed again, like entering the same data again into a DB.

This brief article was written by
apollois
http://www.experts-exchange.com/memberProfile.jsp?mbr=apollois
Experts-Exchange ASP Expert

THE SOLUTION:
Previously the "best" solution was to redirect to a third page.  But if the confirmation page displays most (all) of the data submitted, this is a lot of extra work.  The new solution I have developed is to check the date/time stamp of the form when it is submitted.  If it is the same, then this is due to a browser refresh, so just ignore the post, or take whatever action you desire.

Let's examine this  in detail.

First, the basic process.  The form in in page MyForm.asp.  It is POSTed to ProcessData.asp which updates a database, and then displays a detailed confirmation to the user.

The key is to create a hidden form field in Myform.asp.  It should be unique to your application, so let's call it "Myform_DTStamp".  When the form is submitted, it should update this field prior to submittal with the browsers local date/time to the nearest millisecond.  

The form is posted to ProcessData.asp.  It reads the "Myform_DTStamp" and compares it to a Session variable by the same name.  If the values are identical, then you do NOT process the data because it is due to a browser refresh.  If the values are different, then this is either the first post, or a different post from the form, so process the form data as normal.  Save the DTSamp form field as a Session variable by the same name.

The Processdata.asp confirmation is displayed to the user.  If the user clicks the browser's refresh button, or presses F5, he/she will most likely get an alert like:

====================================================================
The page cannot be refreshed without resending the information.
Click Retry to send the information again, or click Cancel to return to the page that you were trying to view.

            [Retry]            [Cancel]
===================================================================

If the user clicks "Retry" the browser will resubmit the exact same form data, including the "Myform_DTStamp".  Thus when ProcessData.asp receives it, the Session("MyForm_DTStamp") will equal the Request.form("Myform_DTStamp").  So you will know it is due to refresh, and do not save the data to the database.  I just display a message "Do not refresh this  page."

So let's take a look at the code.  It takes a lot less to write the code than to explain it. <bg>

~~~~~~~~~~ Myform.asp ~~~~~~~~~~~~~~

========================================================
<HTML>
<HEAD>
<SCRIPT LANGUAGE=javascript>
<!--

//================================================================
function now() {
//================================================================
      //PURPOSE:  Returns the current date/time to the nearest millisecond.
      
      var dNow, sDateTime = " ";
      var c = ":";
      dNow = new Date();

      sDateTime += (dNow.getMonth() + 1) + "/";    //Get month
      sDateTime += dNow.getDate() + "/";           //Get day
      sDateTime += dNow.getYear() + "  ";          //Get year.
      sDateTime += dNow.getHours() + c;
      sDateTime += dNow.getMinutes() + c;
      sDateTime += dNow.getSeconds() + c;
      sDateTime += dNow.getMilliseconds();
      
      return sDateTime;

}

//============================================================
function updateDTS(poForm) {
//============================================================
      //PURPOSE:  Update the hidden DTStamp field with current date/time
      //                  to the nearest millisecond.

      poForm.Myform_DTStamp.value = now();
      return true;
}
-->
</SCRIPT>

</HEAD>
<BODY>

<FORM name="Myform" action="Processdata.asp" method="post"
      onSubmit="updateDTS(this);">
<INPUT type="hidden" name="Myform_DTStamp" value="TBD">

<!--- put your other form fields here --->

<INPUT type="submit" value="Submit">
</FORM>
</BODY>
</HTML>
========================================================


~~~~~~~~~ ProcessData.asp ~~~~~~~~~~~~~~~

================================================================
<%
DIM Myform_DTStamp
DIM sDTStamp

IF Request.Form.Count > 0 THEN

      '--- A FORM WAS SUBMITTED ---

      '--- CHECK FOR BROWSER REFRESH ---
      
      sDTStamp = Request.Form("Myform_DTStamp")
      
      IF Session("Myform_DTStamp") = sDTStamp THEN
      
            '--- PAGE WAS REFRESHED ---
            Response.Write "<H3>Do Not Refresh This Page!</H3>"

            'NOTE:  Take whatever other action you wish.
            
      ELSE
      
            '--- NEW SUBMITTAL - PROCESS FORM DATA ---
            Session("Myform_DTStamp") = sDTStamp
            Response.Write "<H3>Your Form Was Processed/Saved.</H3>"

            'NOTE:  Save data to DB or whatever you wish.

      END IF


ELSE
      '--- PAGE WAS REQUESTED BUT FORM WAS NOT SUBMITTED ---
      Response.Write "<H3>Invalid Access</H3>"

END IF

%>

<html>
<head>
</head>
<body>
<!--- YOUR CONFIRMATION DATA HERE --->
</body>
</html>
================================================================


Best Regards,
>apollois<
0
 
LVL 58

Expert Comment

by:Gary
ID: 9187761
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Accept Answer by MaxOvrdrv2

Please leave any comments here within the next seven days.
 
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
 
GaryC123
EE Cleanup Volunteer
0

Featured Post

Enroll in August's Course of the Month

August's CompTIA IT Fundamentals course includes 19 hours of basic computer principle modules and prepares you for the certification exam. It's free for Premium Members, Team Accounts, and Qualified Experts!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I have helped a lot of people on EE with their coding sources and have enjoyed near about every minute of it. Sometimes it can get a little tedious but it is always a challenge and the one thing that I always say is:   The Exchange of informatio…
I would like to start this tip/trick by saying Thank You, to all who said that this could not be done, as it forced me to make sure that it could be accomplished. :) To start, I want to make sure everyone understands the importance of utilizing p…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question