HTTP 缓存机制介绍

Ø  简介

本文简单讨论 HTTP 缓存机制的基本概念与使用方法,经本人测试得出结论,不对之处欢迎指正。

 

1.  什么是HTTP 缓存

1)   HTTP 缓存其实是一种输出缓存,当第一次请求(可能是A用户)时,以设定的时间缓存响应的HTML 页面,第二次请求(可能是B用户) 时,如果在缓存期内,将使用缓存内容输出,而不会以新的请求处理。

2)   缓存内容会因设定的时间而失效,也有可能因为系统内存紧张,提前移除缓存内容。

 

2.  缓存的优点

1)   减少相同资源重复性的请求,以减少网络宽带的消耗;

2)   减少客户端与服务端的瓶颈,也减轻了服务器的压力;

3)   自然在速度上也有所提高,提高了用户的体验。

 

3.  理解下Request Headers 中缓存标头的意思:

1)   If-Modified-Since: 该值由服务器响应,对此文件的最后修改时间,与 Last-Modified 值相同,会再次发送给服务器。

2)   If-None-Match:该值由服务器响应,服务器对此资源生成的缓存唯一标识,与ETag 值相同,会再次发送给服务器。

 

4.  理解下Response Headers 中缓存标头的意思:

1)   Cache-Control: 字面上就可以理解为缓存控制,包含以下值:

1.   private: 默认值。只能缓存在客户端,而不能由共享(代理服务器)缓存进行缓存。

2.   public: 响应由客户端和共享(代理)缓存进行缓存。

3.   no-cache: 如果没有字段名,则指令应用于整个请求,且在满足请求前,共享(代理服务器)缓存必须对原始Web 服务器强制执行成功的重新验证。如果有字段名,则指令仅应用于命名字段;响应的其余部分可能由共享缓存提供。

4.   max-age=xxx: 表示缓存的最长时间。

5.   no-store: 浏览器和服务器都不使用缓存。

2)   Date: 服务器响应时间。

3)   Expires: 缓存绝对过期时间(HTTP 1.0)

4)   Vary: 告诉代理服务器缓存两种版本的资源:压缩和非压缩,这有助于避免一些公共代理不能正确地检测Content-Encoding标头的问题。可以在 system.webServer 节点中添加,例如:

<system.webServer>

    <httpProtocol>

      <customHeaders>

        <remove name="Vary"></remove>

        <add name="Vary" value="Accept-Encoding"></add>

      </customHeaders>

    </httpProtocol>

  </system.webServer>

5)   Last-Modified: 表示服务器对此文件的最后修改时间。当浏览器第一次请求某一个URL时,服务端的返回状态是200;第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头,询问该时间之后文件是否有被修改过;如果服务端的资源没有变化,则自动返回HTTP 304Not Changed.)状态码,内容为空,这样就节省了传输数据量。

6)   ETag: 表示服务器对此资源生成的缓存唯一标识,与 Last-Modified 功能类似。

 

5.  先看一下非缓存下的请求/响应缓存报文,如图:

clip_image002

 

6.  使用Response.Cache.SetMaxAge() 方法,实现让浏览器在指定的时间内使用浏览器缓存(该方式对于强制刷新无效

1)   添加如下代码:

protected void Page_Load(object sender, EventArgs e)

{  

    Response.Cache.SetCacheability(HttpCacheability.Private);   //可以忽略,因为Private 是默认值

    Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 10));    //设置缓存的最长时间

}

2)  发送请求:http://localhost:50441/Cache/One,并且在缓存期内连续多次刷新页面,将看到如下结果

clip_image004

clip_image006

3)   可以发现在非强制刷新的情况下,若还在缓存期内(10)并未发出新的请求,并且服务器的时间未改变,说明还使用的是缓存。但是,第四次强制刷新,则缓存无效了(即使还在缓存期内)。

 

7.  使用 OutputCache 命令设置缓存,对应Last-Modified If-Modified-Since(该方式对于强制刷新有效

n  Duration设置缓存持续时间(以秒为单位)。

n VaryByParam:表示根据什么参数来更新缓存,可选值:

1.   none:不根据参数更新缓存。

2.   paramNames:表示根据参数名称更新缓存,多个参数以分号(;)分割,例如:"id;name"

3.  *:表示任何参数改变时,都更新缓存。

1)   在页面头部添加以下代码即可:

<%@ OutputCache Duration="10" VaryByParam="none" %>

2)   发送请求:http://localhost:50441/Cache/One连续刷新页面两次,将看到如下结果

clip_image008

clip_image010

clip_image012

3)   可以看出缓存绝对过期时间比服务器响应时间长了10秒,表示在这10秒以内再次请求(无论是强制刷新 还是 超链接刷新等)这个地址,都会使用缓存,即返回304 状态码。

4)   正因如此,在服务端就可以获取到“服务器对此文件的最后修改时间,即 If-Modified-Since 的值,从而判断:该值+ 缓存时间> 当前时间,如果大于表示缓存已过期,则产生一个新的请求,否则输出缓存内容。(这只是我的个人理解)

5)   我们可以使用 Request.Headers["If-Modified-Since"] 来获取客户端传来的“服务器对此文件的最后修改时间”的值,获取上次对该请求设置的值。

 

8.   使用Response.Cache.SetCacheability() 方法也能实现同上的缓存功能,对应Last-Modified If-Modified-Since(该方式对于强制刷新有效)(效果与使用 OutputCache 命令一样,就不截图了),看代码:

protected void Page_Load(object sender, EventArgs e)

{

    Response.Cache.SetCacheability(HttpCacheability.Public);  //这里不设置默认为 Private

    Response.Cache.SetExpires(DateTime.Now.AddSeconds(10));

    //设置服务器自动返回304状态码(该设置对于强制刷新 或 地址栏回车将有效)

    Response.Cache.SetLastModified(DateTime.Now);   //该时间表示服务器对此文件的最后修改时间

    Response.Cache.SetLastModifiedFromFileDependencies(); //基于处理程序文件依赖项的时间戳设置Last-Modified HTTP 标头。

}

 

9.  使用Response.Cache.SetETagFromFileDependencies() 方法也能实现同上的缓存功能,与使用 Response.Cache.SetCacheability() 方法的功能类似,对应ETag If-None-Match(该方式对于强制刷新有效,且 ETag 优先级高于 Last-Modified(没测试)

1)  添加如下代码

protected void Page_Load(object sender, EventArgs e)

{

    Response.Cache.SetCacheability(HttpCacheability.Public);  //这里不设置默认为 Private

    Response.Cache.SetExpires(DateTime.Now.AddSeconds(10));

    //(该方式对于强制刷新有效)

    Response.Cache.SetETagFromFileDependencies();   //基于处理程序文件依赖项的时间戳设置ETag HTTP 标头。

}

2)  发送请求:http://localhost:50441/Cache/One,并且在缓存期内连续两次刷新页面,将看到如下结果

clip_image014

3)  同样,我们可以使用 Request.Headers["If-None-Match"] 来获取客户端传来的“服务器对此资源生成的缓存唯一标识”的值,获取上次对该请求设置的值。

 

10. 使用 System.Web.UI.HtmlControls.HtmlMeta 对象实现(该方式对于强制刷新无效),看代码(注意:这种方式仅支持 IE,其他4大浏览器都不支持):

protected void Page_Load(object sender, EventArgs e)

{

    HtmlMeta htmlMeta = new HtmlMeta();

    htmlMeta.HttpEquiv = "Expires";

    htmlMeta.Content = DateTime.Now.AddSeconds(10).ToUniversalTime().ToString("R"); //这里需要转为GMT 时间

    this.Header.Controls.Add(htmlMeta);

}

posted @ 2022-03-10 23:08  Abeam  阅读(563)  评论(0编辑  收藏  举报