先梳理三个概念:
还有两个 HTTP 状态码:
如果我们的应用程序没有进行任何的缓存处理,客户端在每次浏览页面的时候,Last-Modified 和 If-Modified-Since 的响应值都为 NULL,并且 HTTP 状态码为 200,这没什么问题。我们下面要做的工作先使用 OutputCache 实现缓存,代码很简单:
public static int index = 0;[OutputCache(Duration = 120)]public ActionResult About(){ FileHelper.Write(@"C:/Users/xishuai/Desktop/test.txt", (index+1).ToString()); ViewBag.Message = "Message:" + index++; return View();}
第一次请求:
第二次请求:
第三次请求:
Message 和 test.txt 里面的值一直为 0,Message 是为了测试页面缓存有没有生效,test.txt 是为了测试 About Action 有没有执行,这两个值的测试结果是我们想要的。另外,可以看到,第一次刷新的时候,Last-Modified 是有值的,而 If-Modified-Since 却没有值,这是因为 Last-Modified 是服务器发给客户端,而 If-Modified-Since 的产生必须要要通过 Last-Modified,并且是由客户端发给服务器,这个在第二次刷新的时候就可以看到,在页面输出缓存的 120 秒内,这两个值会一直不变。
dudu 之前的两篇博文:
出现的问题就是我们在第三次请求的时候,HTTP 状态码为 200,之前的解决方式是 Response.Cache.SetOmitVaryStar(true);
,这个我在做测试的时候没有遇到,使用的是 MVC 5.2.2,微软应该是修复了。
上面是 ASP.NET 中使用 OutputCache 进行缓存的处理,我们一般也是这么用的,根据对 Last-Modified 和 If-Modified-Since 的理解,我们能不能使用它们,来实现 OutputCache 的一些效果呢?下面我们来尝试下,简单代码:
public static int index = 0;public ActionResult About(){ string dt = Request.Headers["If-Modified-Since"]; DateTime isModifiedSince; if (!string.IsNullOrEmpty(dt)) { if (DateTime.TryParse(dt, out isModifiedSince)) { if (isModifiedSince.AddSeconds(120) < DateTime.Now) { Response.Cache.SetLastModified(DateTime.Now); } } } else { Response.Cache.SetLastModified(DateTime.Now); } FileHelper.Write(@"C:/Users/xishuai/Desktop/test.txt", (index+1).ToString()); ViewBag.Message = "Message:" + index++; return View();}
先说下上面代码的意思,首先获取请求头中 If-Modified-Since 的值,如果没有值的话,就通过 SetLastModified 设置响应头中 Last-Modified 的值,如果有值的话,进行时间间隔判断,如果在 120 秒之外,则更新 Last-Modified 的值,否则不更新,我们来看下测试结果。
第一次请求:
第二次请求:
第三次请求:
这是什么情况?和 OutputCache 的效果也差太多了吧,总的来说,HTTP 的状态码一直为 200,test.txt 和 Message 的值一直在发生变化,也就是说“缓存”没有一点效果,而 Last-Modified 和 If-Modified-Since 则更奇怪,一会有值,一会没值。其实很正常,如果 HTTP 的状态码为 200,当一个请求发起的时候,首先设置 Last-Modified 的值,而 If-Modified-Since 则是在下个请求才能生效,因为生效了,所以第二次请求的时候,我们并没有设置 Last-Modified 的值,所以第一次和第二次的请求结果就是上面所示,下面的请求就是重复第一次和第二次请求。
我们知道,Last-Modified 和 If-Modified-Since 的结果和 HTTP 的状态码有关,下面我们再来修改下代码:
public static int index = 0;public ActionResult About(){ string dt = Request.Headers["If-Modified-Since"]; DateTime isModifiedSince; if (!string.IsNullOrEmpty(dt)) { if (DateTime.TryParse(dt, out isModifiedSince)) { if (isModifiedSince.AddSeconds(120) < DateTime.Now) { Response.Cache.SetLastModified(DateTime.Now); Response.StatusCode = 200; } else { Response.StatusCode = 304; } } else { Response.StatusCode = 304; } } else { Response.Cache.SetLastModified(DateTime.Now); Response.StatusCode = 200; } FileHelper.Write(@"C:/Users/xishuai/Desktop/test.txt", (index+1).ToString()); ViewBag.Message = "Message:" + index++; return View();}
你可以看到我们想要做的目的吧,就是手动设置 HTTP 状态码,我们来看下测试结果。
第一次请求:
第二次请求:
第三次请求:
说实话,就差一点和 OutputCache 的效果一样,那差的是什么呢?其实就是 test.txt 里的值,在使用 OutputCache 的时候,这里面的值是不变的,也就是说 About Action 没有被执行,而我们上面测试显示,About Action 是执行的,对于 Message 来说,浏览器显示的是缓存后的值,我们可以得出这样的结论:当使用 OutputCache 的时候,客户端只是向服务器发起一个 Request,仅此而已,这个我们在 application_BeginRequest 事件中监控到,其余的页面显示完全是客户端缓存的结果,当然,前提方式缓存方式是客户端。
还有一个有意思的地方是,在使用 OutputCache 的时候,除了第一次请求外,其他请求结果中,Last-Modified 和 If-Modified-Since 的值是不变的,根据上面测试的结果,我们可以得出,If-Modified-Since 是 Last-Modified 设置之后的结果,If-Modified-Since 可以一直不变,只要 HTTP 状态码为 304,并且我们没有对 Last-Modified 进行设置。而在使用 OutputCache 的时候,除了 If-Modified-Since 的值一直没变,Last-Modified 的也一直没变,这个有点诡异,应该是把请求和响应头中的值也进行了缓存。
参考资料:
新闻热点
疑难解答