您的位置:首页 > 编程语言 > ASP

在ASP.NET Web Form和MVC中防止F5刷新引起的重复提交

2012-03-29 15:59 681 查看

什么是刷新/重新载入

IE中的刷新(Refresh),在FF和Chrome中称为重新载入(Reload),与正常进入页面的区别在于以下两点:

1. 缓存控制

如果文件(比如图片)在本地缓存中已经存在,正常进入页面会不访问服务器而直接从本地加载。而对于刷新操作,即使存在本地缓存,也会强制访问服务器检查更新,在Request Header中会带有“If-Modified-Since”标签。如果文件没有更新,服务器会返回304, 否则返回200及更新后的文件。

2. 重复提交

刷新会重复提交上一次的请求。比方说新建一张订单然后保存,而系统操作成功后停留在当前页面。此时进行刷新,浏览器会弹出一个对话框询问是否继续,点确定后浏览器会重复提交上一次的POST请求(点击保存的请求),系统可能会产生一张重复的订单。当然,上次操作如果只是Get请求而非POST,重复提交并不会导致这种问题。

如何防止重复提交

防止重复提交的方法与PRG(POST-Redirect-GET)模式有一些相似之处,具体来说,当Web服务器识别到一个重复提交的POST请求的时候,重定向到当前页面,然后浏览器以GET的方式请求该页面。如果使用HttpWatch之类的工具查看网络请求,可以看到会有两个请求,302 & 200。

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


避免IE 8及之前版本的Bug

再此过程中发现IE8及之前IE版本中的一个Bug。在刷新操作中进行重定向到当前路径,IE9/Chrome/Firefox中会产生两个请求,302和200,但是在IE8中,在302后没有进行重定向,页面则变成空白页。

IE9/Chrome/Firefox: (正常)





IE8 and ealier: (异常)





并不清楚这是IE8的缺陷还是所谓by-designed的行为。为了避免这种情况,在上述两种实现中都在重定向的URL中加了一个时间戳,使之与原路径不一样来避免此问题。

该方案的限制性

由于我们使用Session来存放服务器端的标志位,所以当用户在同一浏览器中不同标签页打开同一个页面时会有些小问题。后面打开的标签页一切正常,但如果在上面做了一些操作后又回到前面打开的标签操作,会引起先打开的标签重定向。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: