什么是刷新/重新载入
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。
现在问题在于如何识别一个请求是由刷新引起的。我们利用刷新操作会重复提交上一次请求,而不是当前请求的特性,可以有以下方案:在服务器端(Session)和页面(可以是页面上一个hidden field)上都设置一个整型标志位,在每次POST请求中都比较两者的值,然后自增。在正常提交情况下,浏览器会提交当前页面上hidden field的值,所以每次该值与Session中的都相等;在刷新情况下,提交的值是上次请求的值,就会与Session的不相等,由此得知是刷新操作引起的重复提交。
这类似于Struts中的Token验证。
在这里我们把页面hidden field称为Client Flag,具体的流程如下
在最后一步刷新页面的时候,hidden field的值为3,但是浏览器会重复提交上一次的请求(2),造成与Session中的值(3)不一致。
在ASP.NET MVC中的实现
添加一个自定义的ActionFilter.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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