What is Refresh/reload?
Refresh in IE is called reload in ff and chrome. The difference between reload and normal page access is as follows:
1. Cache Control
If a file (slice) already exists in the local cache, normal access to the page will directly load from the local without accessing the server. For the refresh operation, even if the local cache exists, the server will be forcibly accessed to check for updates. The request header will contain the "if-modified-since" label. If the file is not updated, the server returns 304; otherwise, the server returns 200 and the updated file.
2. Submit again
Refresh will submit the last request again. For example, you can create an order and save it. After the system operation is successful, it stays on the current page. Refresh now. the browser will pop up a dialog box asking if you want to continue. After clicking OK, the browser will submit the last post request again (click to save the request ), the system may generate a duplicate order. Of course, if the last operation was only a GET request rather than a POST request, repeated submission would not cause this problem.
How to prevent repeated submission
The method to prevent repeated submission has some similarities with the PRG (post-redirect-Get) mode. Specifically, when the web server identifies a repeated POST request, redirect to the current page, and then the browser requests the page in get mode. If you use tools such as httpwatch to view network requests, you can see two requests, 302 & 200.
The problem now is how to identify a request that is caused by refresh. The refresh operation will repeat the previous request, instead of the features of the current request. The following solutions are available: Session and page (which can be a hidden field on the page) set an integer flag, compare the values of the two in each POST request, and then auto-increment. Under normal submission, the browser will submit the value of the hidden field on the current page, so each time this value is equal to the value in the session; When refreshing, the submitted value is the value of the previous request, which is inconsistent with the session. It is known that the refresh operation causes repeated submission.
This is similar to the token verification in struts.
Here we call the page hidden field client flag. The specific process is as follows:
When refreshing the page in the last step, the value of the hidden field is 3, but the browser will submit the last request again (2), causing inconsistency with the value (3) in the session.
Implementation in ASP. NET MVC
Add a custom actionfilter.
View code
Public Class Noresubmitattribute: actionfilterattribute { Private Static Readonly String Httpmehotdpost = " Post " ; Private Static Readonly String Prefix = " Postflag " ; Private String Namewithroute; Public Override Void Onactionexecuting (actionexecutingcontext filtercontext ){ VaR Controllercontext = Filtercontext. Controller. controllercontext; If (! Controllercontext. ischildaction ){ VaR Request = Controllercontext. httpcontext. request; VaR Session = Controllercontext. httpcontext. Session; namewithroute = Generatenamewithroute (controllercontext ); Int Sessionflag = session [namewithroute] = Null ? 0 :( Int ) Session [namewithroute]; Int Requestflag = String . Isnullorempty (request. Form [namewithroute])? 0 : Int . Parse (request. Form [namewithroute]); // Get or normal post: true; Bool Isvalid =! Ispost (filtercontext) | sessionflag = Requestflag; If (Sessionflag = Int . Maxvalue) {sessionflag =- 1 ;} Session [namewithroute] = ++ Sessionflag; If (! Isvalid) {filtercontext. Result = New Redirectresult (generateurlwithtimestamp (request. rawurl )); Return ;}} Base . Onactionexecuting (filtercontext );} Private String Generateurlwithtimestamp ( String URL ){ Return String . Format ( " {0} {1} timestamp = {2} " , URL, URL. Contains ( " ? " )? " & " : " ? " , (Datetime. Now-datetime. parse ( " 2010/01/01 " ). Ticks );} Private Bool Ispost (actionexecutingcontext filtercontext ){ Return Filtercontext. httpcontext. Request. httpmethod = Httpmehotdpost ;} Private String Generatenamewithroute (controllercontext) {stringbuilder sb = New Stringbuilder (prefix ); Foreach ( Object Routevalue In Controllercontext. routedata. Values. Values) {sb. appendformat ( " _ {0} " , Routevalue );} Return SB. tostring ();} Public Override Void Onresultexecuted (resultexecutedcontext filtercontext ){ Base . Onresultexecuted (filtercontext ); If (! Filtercontext. ischildaction &&! (Filtercontext. Result Is Redirectresult )){ // String format = "<SCRIPT type = 'text/JavaScript '> $ (function () [[$ ('form '). each (function () [[$ ('<input type = hidden id = {0} name = {0} value = {1}/> '). appendto ($ (this);]); </SCRIPT> "; String Format = " <SCRIPT type = 'text/JavaScript '> var forms = document. getelementsbytagname ('form'); For (VAR I = 0; I <forms. length; I ++) [[Var ele = document. createelement ('input'); ELE. type = 'siden'; ELE. id = ELE. name = '{0}'; ELE. value = '{1}'; forms [I]. appendchild (Ele);] </SCRIPT> " ; String Script = String . Format (format, namewithroute, filtercontext. httpcontext. session [namewithroute]). Replace ( " [[ " , " { " ). Replace ( " ] " , " } " ); Filtercontext. httpcontext. response. Write (SCRIPT );}}}
For ease of submission, the section for creating hiddenfield through JavaScript is also encapsulated in actionfilter. Of course, you can also add this hiddenfield on the parent page.
Add this attribute to the action to prevent repeated submissions,Note that this attribute must be added for get and post actions, or none of them must be added..
View code
[Httpget] [noresubmit]PublicActionresult index (){ReturnView ();} [httppost] [noresubmit]PublicActionresult index (IntID ){ReturnView ();} [noresubmit]PublicActionresult about (){ReturnView ();}
Implementation in ASP. NET web form
Like MVC, we can still use the hidden field method in web form, but I prefer to use viewstate to store this flag, in this way, you are not allowed to dynamically create a hidden field.
The implementation is placed in a basepage class inherited from web. UI. Page. You only need to inherit the basepage from the page class.
View code
Public Class Basepage: system. Web. UI. Page { Private Static Readonly String Prefix = " Postflag " ; Private String Namewithroute; Public Basepage () {namewithroute = Generatenamewithroute ();} Protected Override Void Loadviewstate ( Object Savedstate ){ Object [] Allstates = ( Object []) Savedstate; Base . Loadviewstate (allstates [ 0 ]); Int Requestflag = String . Isnullorempty (allstates [ 1 ]. Tostring ())? 0 : Int . Parse (allstates [ 1 ]. Tostring ()); Int Sessionflag = session [namewithroute] = Null ? 0 :( Int ) Session [namewithroute]; // Get or normal post: true; Bool Isvalid =! Ispostback | sessionflag = Requestflag; If (Sessionflag = Int . Maxvalue) {sessionflag =- 1 ;} Session [namewithroute] = ++ Sessionflag; If (! Isvalid) {response. Redirect (generateurlwithtimestamp (request. rawurl ), False ); Response. End (); Return ;}} Protected Override Object Saveviewstate (){ Object [] Allstates = New Object [ 2 ]; Allstates [ 0 ] = Base . Saveviewstate (); allstates [ 1 ] = Session [namewithroute]; Return Allstates ;} Private String Generatenamewithroute (){ String Filesubfix = " . Aspx " ; Return Prefix + request. filepath. Replace (filesubfix, "" ). Replace ( " / " , " _ " );} Private String Generateurlwithtimestamp ( String URL ){ Return String . Format ( " {0} {1} timestamp = {2} " , URL, URL. Contains ( " ? " )? " & " : " ? " , (Datetime. Now-datetime. parse ( " 2010/01/01 " ). Ticks );}}
Avoid bugs in IE 8 and earlier versions
In this process, we found a bug in IE8 and earlier ie versions. In the refresh operation, redirect to the current path. ie9/Chrome/Firefox will generate two requests, 302 and 200, but in IE8, no redirection is performed after 302, the page becomes a blank page.
Ie9/Chrome/Firefox: (normal)
IE8 and ealier: (exception)
It is unclear whether this is a defect of IE8 or a behavior called by-designed. To avoid this problem, a timestamp is added to the Redirection URL in the preceding two implementations so that the timestamp is different from the original path to avoid this problem.
Restrictions of the Solution
Because session is used to store the server's flag space, it may cause minor problems when users open the same page on different tabs in the same browser. The tabs opened later are all normal, but if you perform some operations above and then return to the previously opened tag operation, the first opened tag redirection will occur.