Last-Modified、If-Modified-Since 实现缓存和 OutputCache 的区别
先梳理三个概念:
- OutputCache:页面输出缓存,一般 ASP.NET 应用程序会用到。
- Last-Modified:Http 响应头(Http Reponse Header),由服务器发给客户端,格式为 Last-Modified:Tue, 24 Mar 2015 06:40:46 GMT
- If-Modified-Since:Http 请求头(Http Request Header),由客户端发给服务器,格式为 If-Modified-Since:Tue, 24 Mar 2015 06:40:46 GMT
还有两个 HTTP 状态码:
- 200(成功):正常状态,服务器已成功处理了请求,每次都有客户端和服务端的交互。
- 304(未修改):自从上次请求后,请求的网页未修改过,服务器返回此响应时,不会返回网页内容。如果网页自请求者上次请求后再也没有更改过,将服务器配置为返回此响应(If-Modified-Since 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();
}
第一次请求:
- Status Code:200
- Last-Modified:Tue, 24 Mar 2015 07:13:46 GMT
- If-Modified-Since:NULL
- test.txt:0
- Message:0
第二次请求:
- Status Code:304
- Last-Modified:Tue, 24 Mar 2015 07:13:46 GMT
- If-Modified-Since:Tue, 24 Mar 2015 07:13:46 GMT
- test.txt:0
- Message:0
第三次请求:
- Status Code:304
- Last-Modified:Tue, 24 Mar 2015 07:13:46 GMT
- If-Modified-Since:Tue, 24 Mar 2015 07:13:46 GMT
- test.txt:0
- Message:0
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 的值,否则不更新,我们来看下测试结果。
第一次请求:
- Status Code:200
- Last-Modified:Tue, 24 Mar 2015 07:34:58 GMT
- If-Modified-Since:NULL
- test.txt:0
- Message:0
第二次请求:
- Status Code:200
- Last-Modified:NULL
- If-Modified-Since:Tue, 24 Mar 2015 07:35:46 GMT
- test.txt:1
- Message:1
第三次请求:
- Status Code:200
- Last-Modified:Tue, 24 Mar 2015 07:36:03 GMT
- If-Modified-Since:NULL
- test.txt:2
- Message:2
这是什么情况?和 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 状态码,我们来看下测试结果。
第一次请求:
- Status Code:200
- Last-Modified:Tue, 24 Mar 2015 07:49:07 GMT
- If-Modified-Since:NULL
- test.txt:0
- Message:0
第二次请求:
- Status Code:304
- Last-Modified:NULL
- If-Modified-Since:Tue, 24 Mar 2015 07:49:07 GMT
- test.txt:1
- Message:0
第三次请求:
- Status Code:304
- Last-Modified:NULL
- If-Modified-Since:Tue, 24 Mar 2015 07:49:07 GMT
- test.txt:2
- Message:0
说实话,就差一点和 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 的也一直没变,这个有点诡异,应该是把请求和响应头中的值也进行了缓存。
参考资料:
- 影响Cache的几个HTTP头信息
- 有关Last-Modified 与 If-Modified-Since
- HTTP的请求头标签 If-Modified-Since
- Last-Modified Header in MVC
Last-Modified、If-Modified-Since 实现缓存和 OutputCache 的区别的更多相关文章
- modified: xxx(modified content, untracked content)
当运行git status的时候提示如下: modified: xxx(modified content, untracked content) 我们会很本能的直接执行 add .commit .pu ...
- hibernate的flush()、refresh()、clear()针对一级缓存的操作的区别
首先session是有一级缓存的,目的是为了减少查询数据库的时间,提高效率,一级缓存的生命周期和session是一样的, session.flush()和session.clear()就针对sessi ...
- 我用ASP.NET缓存之OutputCache
[我的理解]页面缓存常用在网站上.Web应用系统上也用,但由于Web系统常与数据库打交道.时效性要求蛮强的,所以是否能用缓存得具体情况具体分析(很喜欢这句话“具体情况具体分析”,很符合国人的中庸之道) ...
- 缓冲区Buffer和缓存区Cache的区别
1.buffer 将数据写入到内存里,这个数据的内存空间在Linux系统里一般被称为缓冲区(buffer),例如:写入到内存buffer缓冲区,即写缓冲. 为了提高写操作性能,数据在写入最终介质或下一 ...
- Vue的计算属性缓存和method的区别在哪?
一.先看一个例子 <div id="example"> {{ message.split('').reverse().join('') }} </div> ...
- SpringMVC的缓存对静态资源的影响 304 Not Modified
我们知道在springmvc的配置中,可以添加缓存,但是缓存到底对静态资源有什么影响? 测试 没有添加缓存 <mvc:resources mapping="/image/**" ...
- What is the difference between modified duration, effective duration and duration?
Macaulay Duration (traditionally just called Duration) The formula usually used to calculate a bond' ...
- 前端学HTTP之缓存
前面的话 Web缓存是可以自动保存常见文档副本的HTTP设备.当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这个文档.本文将详细介绍缓存的相关内容 功能 ...
- nginx,控浏览器缓存,前端优化方案
1,困惑 做web项目,对于开发者来说,一个最头痛的问题就是浏览器缓存,有缓存,js更改了,html更改了,发布服务器以后用户往往无法通过浏览器访问到最新的类容,需要用户主动去刷新页面, 因为一直做企 ...
随机推荐
- ViewController的生命周期
# ViewController 的生命周期 # ViewController的生命周期中各个方法的流程如下: init loadView :加载view viewDidLoad :view加载完毕 ...
- JQuery实现Ajax应用
将自己之前在印象笔记的笔记搬家了~ 1.使用 load()方法异步请求数据,通过Ajax 请求加载服务器中的数据,并把返回的数据放置到指定的元素中,它的调用格式为: load(url,[data],[ ...
- Python模块之常用模块,反射以及正则表达式
常用模块 1. OS模块 用于提供系统级别的操作,系统目录,文件,路径,环境变量等 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("di ...
- 破除Odoo 菜单栏提示 99+
菜单栏提示利用的menu对象的needaction_counter属性,默认只能显示99个 多于99则显示99+ 如果希望显示完整的数字,则需要改动如下两个地方. 一.menu菜单的显示限制: 将第一 ...
- Django models知识小点
django 为使用一种新的方式,即关系对象映射(ORM) 一,创建表 1,基本结构 注意: 1,创建标的时候,如果我们不给表加自增列,生成表的时候会默认给我们生成一列为ID的自增列,当然我们也可以自 ...
- CSS基础篇之选择符3
border(边框) 如何用CSS调出边框 我们给p标签加一个边框试一下 p{ border:1px solid #ccc:/*这是缩写*/ } 第一个值是为边框的宽度 第二个值是为边框线样式为直线 ...
- Jquery源码学习(第一天)
jQuery是面向对象的设计通过window.$ = window.jQuery = $; 向外提供接口,将$挂在window下,外部就可以使用$和jQuery $("#div1" ...
- Unity学习疑问记录之坐标体系
[Unity3D的四种坐标系] 1.World Space(世界坐标):我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的.transform.position可以获得该位置坐标. ...
- 剑指Offer面试题:25.二叉搜索树与双向链表
一.题目:二叉搜索树与双向链表 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向.比如输入下图中左边的二叉搜索树,则输出转换之后的 ...
- SQL Server 复制订阅
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/高性能解决方案/高可用 概述 配置复制就没有数据库镜像和AlwaysOn的要求那么高,只需要两台服务器能通过TCP进行通讯即可,两 ...