Expires、Cache-Control、Last-Modified和If-Modified—Since、Etag和If-None-Match

参考文章:Expires、Cache-Control、Last-Modified和If-Modified—Since、Etag和If-None-Match_yangyang的专栏-CSDN博客

http两种缓存:

强制缓存:Cache-Control:public/private/no-cache/no-store/max-age=xxx

     Expires过期时间,绝对时间服务器时间有本地时间不一致会导致缓存失效

协商缓存:  第一次请求后响应参数Etag  <---->第二次请求参数 If-None-Match(比较值是否相同)

  第一次请求后响应参数Last-modified<----->请求参数If-Modify-since(比较时间是否相同)

  优先级:Pragma>Cache-Control>Expires>Etag>Last-modify   (下面有各个缓存的解释)

关于 Cache-Control: max-age=秒 和 Expires

Expires = 时间,HTTP 1.0 版本,缓存的载止时间,允许客户端在这个时间之前不去检查(发请求)
max-age = 秒,HTTP 1.1版本,资源在本地缓存多少秒。

如果max-age和Expires同时存在,则被Cache-Control的max-age覆盖。

Expires 的一个缺点就是,返回的到期时间是服务器端的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大,那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代。

Expires =max-age + “每次下载时的当前的request时间”

所以一旦重新下载的页面后,expires就重新计算一次,但last-modified不会变化 。

缓存控制

在http中,控制缓存开关的字段有两个:Pragma 和 Cache-Control。

1.Pragma
Pragma旧社会遗留(基本废弃使用)。Pragma的值为no-cache时,表示禁用缓存。
Pragma是旧产物,已经逐步抛弃,有些网站为了向下兼容还保留了这两个字段。如果一个报文中同时出现Pragma和Cache-Control时,以Pragma为准。同时出现Cache-Control和Expires时,以Cache-Control为准。即优先级从高到低是 Pragma -> Cache-Control -> Expires

2.Cache-Control

Cache-Control 是指缓存指令,这个指令控制谁在什么条件下可以缓存响应,以及可以缓存多久。这个协定取代了以前的 Expires 指令,在 HTTP/1.1 开始支持,在这么长时间后,我们可以认为 Cache-Control 在正常环境下都是支持的。Cache-Control的格式如下:

Cache-control: must-revalidate
Cache-control: no-cache
Cache-control: no-store
Cache-control: no-transform
Cache-control: public
Cache-control: private
Cache-control: proxy-revalidate
Cache-Control: max-age= //Cathe-Control:max-age=315360000
Cache-control: s-maxage=

 

谁可以缓存

public 与 private 用来指定谁可以缓存。public 是指任何资源都可以被缓存下来,即使某些部分需要 http 验证的情况下; private 则是要求针对单一用户进行缓存,其他用户是无法使用这一块缓存的。

怎么缓存

no-cache,no-store 与 no-transform 来指定怎么缓存。“no-cache”表示必须先与服务器确认返回的响应是否发生了变化,然后才能使用该响应来满足后续对同一网址的请求。因此,如果存在合适的校验值 (ETag),no-cache 会发起往返通信来验证缓存的响应,但如果资源未发生变化,则可避免下载。相比之下,“no-store”则要简单得多。它直接禁止浏览器以及所有中间缓存存储任何版本的返回响应,例如,包含个人隐私数据或银行业务数据的响应。每次用户请求该资产时,都会向服务器发送请求,并下载完整的响应。如果没有指定这个字段,那么就认为是可以缓存的。

缓存多久

指令指定从请求的时间开始,允许获取的响应被重用的最长时间(单位:秒)。例如,max-age=60 表示可在接下来的 60 秒缓存和重用响应。

参考文章:https://blog.csdn.net/u014465934/article/details/83796427

3.Last-Modified和If-Modified—Since

Web页面设计中,建少HTTP请求可以提高页面响应速度。浏览器在第一次访问页面时下载的资源会缓存起来,第二次访问时会判断在缓存中是否已有该资源并且有没有更新过,如果已有该资源且没有更新过,则去缓存去取,这样减少了下载资源的时间。

原理上是通过HTTP Rquest Header中的 if-modified-since 和Response Headers中的last-modified来实现(还有一对组合If-None-Match和Etag,类似,但有细微差别,如有兴趣可参考链接Google Developers 优化性能指导)。

HTTP请求把if-modified-sincede 时间传给服务端,服务端把last-modified时间与之对比,如果相同,则意味着文件没有改动,则返回304,浏览器则从缓存中获取资源,无需下载。

虽然这种方法减少了已缓存资源的下载时间,但是仍然发起了一次http请求。仍然还有更激进的做法来节省也页面加载的时间,就是免去该资源的http请求。即本文的主角,HTTP的Expires和Cache-Control。

Expires、Cache-Control、Last-Modified和If-Modified—Since、Etag和If-None-Match_第1张图片

 

  1. 当Cache-Control设置为max-age=xx并且同时设置Expires时,Cache-Control的优先级更高
  2. 当ETag和Last-Modified同时存在时,服务器先会检查ETag,然后再检查Last-Modified,最终决定返回304还是200

4.Etag和If-None-Match

还记得前面提交的 Etag 吗?这是从另一种维度上来确定 Cache 是否需要更新。服务端会返回相应的 Etag,这个 Etag 客户端不用关心其具体是怎么实现的,只需要能够记录下这个值就行。服务端是通过对内容进行 hash,或者别的算法来生成这样的 Etag,当客户端请求的时候,只需要去检查两者是否相同,即可知道内容有没有发生变化。返回的方式,与前面 If-Modified-Since and Last-Modified 相同。

最新修改日期(Last-Modified)

例如请求:GET googlelogo_color_272x92dp.png HTTP 1.1 Host: www.google.com.hk

       响应:GET googlelogo_color_272x92dp.png HTTP 1.1 Host: www.google.com.hk

再 请 求 :GET googlelogo_color_272x92dp.png HTTP 1.1

                  If-Modified-Since:Fri, 04 Sep    2015 22:33:08 GMT

                  Host: www.google.com.hk

再 响 应 :HTTP 1.1 304 Not Modified(或200状态)

实体标签ETag

例如请求:GET /i/yahoo/gif HTTP 1.1  Host: us.yimg.com

       响应:HTTP 1.1 200 OK

                 Last-Modified:Tue,12 Dec 200603:03:59 GMT

                  ETag:”10c24bc-4ab-457elc1f“

再 请 求 :GET /i/yahoo/gif HTTP 1.1

                Host: us.yimg.com

                If-Modified-Since:Tue,12 Dec 200603:03:59 GMT

                If-None-Match:”10c24bc-4ab-457elc1f“

再 响 应 :HTTP 1.1 304 Not Modified(或200状态)

什么是ETag?

实体标签(EntityTag)是唯一标识了一个组件的一个特定版本的字符串,是web服务器用于确认缓存组件的有效性的一种机制,通常可以使用组件的某些属性来构造它。

为什么要引入Etag?

ETag主要是为了解决Last-Modified无法解决的一些问题:

1.一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;

2.某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);

3.某些服务器不能精确的得到文件的最后修改时间。

Etag带来的问题

ETag的问题在于通常使用某些属性来构造它,有些属性对于特定的部署了网站的服务器来说是唯一的。当使用集群服务器的时候,浏览器从一台服务器上获取了原始组件,之后又向另外一台不同的服务器发起条件GET请求,ETag就会出现不匹配的状况。例如:使用inode-size-timestamp来生成ETag,文件系统使用inode存储文件类型、所有者、组和访问模式等信息,在多台服务器上,就算文件大小、权限、时间戳等都相同,inode也是不同的。

 

综合比较

Expires、Cache-Control、Last-Modified和If-Modified—Since、Etag和If-None-Match_第2张图片

 

1.浏览器会先查询Cache-Control(这里用Expires判断也是可以的,但是Expires一般设置的是绝对过期时间,在HTTP1.1之前较为通用,Cache-Control设置的是相对过期时间,HTTP1.1后推荐使用Cache-Control来控制,如果两者都设置了,则只有Cache-Control的设置生效)来判断内容是否过期,如果未过期,则直接读取浏览器缓存文件,不发送HTTP请求,则进入下一步。

2.在浏览器端判断上次文件返回头中是否含有Etag信息,有则带上If—None—Match字段信息发送请求给服务器,服务器判断Etag未修改则返回304,如果修改则返回200,否则进入下一步。

3.在浏览器端判断上次文件返回头中是否含有Last-Modified信息,有则带上If-Modified-Since字段信息发送请求,服务端判断Last-Modified失效则返回200,有效则返回304。

4.如果Etag和Last-Modified都不存在,则直接向服务器请求内容。

你可能感兴趣的:(webview,android,web,java,html5)