开发者社区> 范大脚脚> 正文

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 的也一直没变,这个有点诡异,应该是把请求和响应头中的值也进行了缓存。

参考资料:


本文转自田园里的蟋蟀博客园博客,原文链接:http://www.cnblogs.com/xishuai/p/aspnet-OutputCache-Last-Modified-If-Modified-Since.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【数据库设计与实现】第7章:缓存与检查点
缓存与检查点设计原则数据缓冲区与检查点是相辅相成的,所以放在同一个章节介绍。由于CPU与持久化设备之间存在巨大的速度差距,所以在内存中引入缓冲区缩小这个差距。从读的角度来看,将热点数据或预判用户可能读取的数据提前加载到内存中,从而将持久化设备的读时延和带宽提升至内存的时延和带宽。从写的角度来看,直接修改缓冲区中的数据而不是磁盘中的数据,可以带来两方面的优势。其一,将持久化设备的写时延和带宽提升至内
45 0
java 实现读取txt文件,反射创建对象,android 手机缓存文件目录
java 实现读取txt文件,反射创建对象,android 手机缓存文件目录
109 0
基于LinkedHashMap实现LRU缓存
基于LinkedHashMap实现LRU缓存
61 0
如何使用 LinkedHashMap 实现 LRU 缓存?
在上一篇文章里,我们聊到了 HashMap 的实现原理和源码分析,在源码分析的过程中,我们发现一些 LinkedHashMap 相关的源码,当时没有展开,现在它来了。 那么,LinkedHashMap 与 HashMap 有什么区别呢?其实,LinkedHashMap 的使用场景非常明确 —— LRU 缓存。今天,我们就来讨论 LinkedHashMap 是如何实现 LRU 缓存的。
34 0
手把手使用 PHP 实现 LRU 缓存淘汰算法
手把手使用 PHP 实现 LRU 缓存淘汰算法
68 0
SparkStreaming+Kafka 实现统计基于缓存的实时uv
SparkStreaming+Kafka 实现统计基于缓存的实时uv
56 0
SparkStreaming+Kafka 实现基于缓存的实时wordcount程序
SparkStreaming+Kafka 实现基于缓存的实时wordcount程序
45 0
基于注解实现缓存的框架 -- SpringCache
Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能,大大简化我们在业务中操作缓存的代码。
63 0
js: 实现一个cached缓存函数计算结果
js: 实现一个cached缓存函数计算结果
104 0
SpringBoot2.x系列教程40--SpringBoot中默认的缓存实现方案
前言 在上一节中,壹哥 带大家学习了Spring Boot中提供的缓存实现方案,尤其是Spring Cache这种实现方案,接下来在本章节中,我将带大家通过代码来具体实现缓存功能。 一. Spring Boot实现默认缓存 1. 创建Web项目 我们按照之前的经验,创建一个SpringBoot的Web程序,具体过程略。 2. 添加依赖包 在pom.xml文件中添加如下核心依赖包。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</
232 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
分布式高并发缓存6.0
立即下载
高并发分布式缓存Redis6.0
立即下载
基于英特尔 SSD 的虚拟机缓存解决SSD
立即下载