http协议之缓存


互联网络特有的延迟以及数据传输的成本,制约互联网快速获取Web资源。为此,HTTP协议引入缓存以空间换时间,使浏览器缓存和重用已获取的资源,解决网络延迟和数据传输成本高的问题,提升访问体验。随着HTTP协议1.0->1.1->2的演进,关于缓存控制的部分有一些变化。在开发Web服务时,首先要关注请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag、响应头Cache-Control。因为这三个HTTP头可以满足你的大部分HTTP缓存需求,当今绝大多数浏览器都支持这三个HTTP头。我们所要做的,就是确保每个服务器响应都提供正确的HTTP头指令,以指导浏览器何时缓存响应以及缓存多久。
缓存的实现原理
1、什么是Web缓存
WEB缓存(cache)位于Web服务器和客户端之间。缓存会根据请求保存输出内容的副本,例如html页面,图片,文件, 当下一个请求来到的时候:如果是相同的URL,缓存直接使用副本响应访问 请求,而不是向源服务器再次发送请求。
HTTP协议定义了相关的消息头来使WEB缓存尽可能好的工作。
2、缓存的优点
减少相应 延迟:因为请求从缓存服务器(离客户端更近)而不是源 服务器被相应,这个过程耗时更少,让web服务器看上去相应更快。
减少网络 带宽消耗:当副本被重用时会减低客户端的带宽消耗;客 户可以节省带宽费用,控制带宽的需求的增长并更易于管理。
3、与缓存相关的HTTP扩展消息头
Expires:指示响应内容过期的时间,格林威治时间GMT
Cache-Control:更细致的控制缓存的内容
Last-Modified:响应中资源最后一次修改的时间
ETag:响应中资源的校验值,在服务器上某个时段是唯一标识的。
Date:服务器的时间
If-Modified-Since:客户端存取的该资源最后一次修改的时间,同Last-Modified。
If-None-Match:客户端存取的该资源的检验值,同ETag。
4、客户端缓存生效的常见流程
服务器收到请求时,会在200OK中回送该资源的Last-Modified和ETag头,客户端将该资源保存在cache中,并记录这两个属性。当客户端需要发送相同的请求时,会在请求中携带If-Modified-Since和If-None-Match两个头。两个头的值分别是响应中Last-Modified和ETag头的值。 服务器通过这两个头判断本地资源未发生变化,客户端不需要重新下载,返回304响应。
5、Web缓存机制
HTTP/1.1中缓存的目的是为了在很多情况下减少发送请求,同时在许多情况下可以不需要发送完整响应。前者减少了网络回路的数量;HTTP利用一个“过期(expiration)”机制来为此目的。后者减少了网络应用的带宽;HTTP用“验证(validation)”机制来为此目的。
HTTP定义了3种缓存机制:
1)Freshness:允许一个回应消息可以在源服务器不被重新检查,并且可以由服务器和客户端来控制。例如,Expires回应头给了一个文档不可用的时间。Cache-Control中的max-age标 识指明了缓存的最长时间;
2)Validation:用来检查以一个缓存的回应是否仍然可用。例如,如果一个回应有一个Last-Modified回应头,缓存能够使用If-Modified-Since来判断是否已改变,以便判断根据情况发送请求;
3)Invalidation: 在另一个请求通过缓存的时候,常常有一个副作用。例如,如果一个URL关联到一个缓存回应,但是其后跟着POST、PUT和DELETE的 请求的话,缓存就会过期。
HTTP缓存在哪里

图1 HTTP缓存在哪里
如图1所示HTTP缓存存在于浏览器和Web代理中。当然在服务器内部,也存在着各种缓存,比如本地缓存GuavaCache/Ehcache,分布式缓存Memcached/Redis等,但这不是本文要讨论的HTTP缓存。所谓的HTTP缓存控制,就是一种协议约定,通过设置不同的响应头Cache-Control来控制浏览器和Web代理对缓存的使用策略,通过设置请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag,来对缓存的有效性进行验证。
本文对请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag、响应头Cache-Control进行实践,分析这三种HTTP缓存头在浏览器和服务器的表现。
注意:由于前端和后端打印时间对象类不一样,将可能打印GMT或者CST时间,GMT比CST晚8小时。
请求头If-Modified-Since/响应头Last-Modified

图2 请求头If-Modified-Since/响应头Last-Modified交互时序图
如图2所示,请求头If-Modified-Since/响应头Last-Modified交互过程如下:
如图2红色部分所示,浏览器第一次向服务器请求资源时,服务器返回状态200和资源内容,同时在响应头Last-Modified字段标记该资源内容在服务器最后被修改时间,格式类似:Last-Modified: Wed, 02 Aug 2017 10:34:50 GMT,供下一次浏览器在请求头If-Modified-Since使用;
如图2紫色部分所示,浏览器第二次向服务器请求该资源时,根据HTTP协议规定,浏览器在请求头If-Modified-Since写入上次服务器返回的响应头Last-Modified值,向服务器询问该时间之后资源是否被修改过,格式类似:If-Modified-Since: Wed, 02 Aug 2017 10:34:50 GMT;
如图2绿色部分所示,当服务器资源文件有修改过,重新返回资源和状态码200给浏览器,同时在响应头Last-Modified字段标记该资源内容在服务器最后被修改时间;
如图2蓝色部分所示,当服务器资源内容没有被修改过,只给浏览器返回状态码304(Not Modified),不返回请求资源,浏览器根据304使用本地缓存,从而节省带宽,提高网页响应速度。
请求头If-None-Match/响应头ETag
ETag全称Entity Tag,用来标识一个Web资源,反映资源内容的变化。在具体的实现中,ETag可以是Web资源的hash值,也可以是一个服务器内部维护的版本号。

图3 请求头If-None-Match/响应头ETag交互时序图
如图3所示,请求头If-None-Match/响应头ETag交互过程如下:
如图3红色部分所示,浏览器第一次向服务器请求资源时,服务器返回状态码200和资源内容,同时在响应头ETag字段标识该资源内容,格式类似:ETag: "50b1a1d4f885c31:df4",供下一次浏览器在请求头If-None-Match使用;
如图3紫色部分所示,浏览器第二次向服务器请求该资源时,根据HTTP协议规定,浏览器在请求头If-None-Match写入上次服务器返回的响应头ETag值,与服务器的资源标识对比后判断资源是否被修改过,格式类似:If-None-Match: "50b1a1d4f885c31:df4";
如图3绿色部分所示,当服务器资源内容有修改过,给浏览器重新返回资源和状态码200,同时在响应头ETag字段标记该资源文件的实体值;
如图3蓝色部分所示,当服务器资源内容没有修改过,只给给浏览器返回状态码304(Not Modified),不返回请求资源,浏览器根据304使用本地缓存,节省带宽,提高网页访问速度。
请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag总结
Last-Modified和Etags如何帮助提高性能
服务端首先产生Last-Modified/Etag标记,并在HTTP响应头返回给客户端,服务端稍后使用它们判断页面是否已经被修改。客户端通过请求头If-Modified-Since/If-None-Match将Last-Modified/Etag标记传回给服务器,要求服务器验证其客户端缓存。过程如下:
1. 客户端请求一个页面A。
2. 服务器返回页面A,并在A加上响应头Last-Modified/ETag。
3. 客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。
4. 客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag作为请求头If-Modified-Since/If-None-Match一起传递给服务器。
5. 服务器检查If-Modified-Since/If-None-Match,判断出该页面自上次客户端请求之后还未被修改,直接返回状态码304和一个空的响应体。
Cache-Control
每个Web资源都可以通过HTTP响应头Cache-Control定义自己的缓存策略,Cache-Control控制谁在什么条件下可以缓存响应以及可以缓存多久。最快的请求是不必与服务器进行通信:通过响应的本地副本,我们可以避免所有的网络延迟以及数据传输的成本。为此,HTTP规范允许服务器返回一系列不同的Cache-Control指令,控制浏览器或者其他中继代理缓存如何缓存某个响应以及缓存多长时间。Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。各个消息中的指令含义如下:
Public指示响应可被任何缓存区缓存。
Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache指示请求或响应消息不能缓存。
no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
Cache-Control响应头在 HTTP/1.1规范中定义,当前的所有浏览器都支持 Cache-Control,取代了之前用来定义响应缓存策略的头例如 Expires。Cache-Control常用的指令包括如下四个,下面将对这四个指令进行详细说明。
max-age
no-cache
no-store
public/private
max-age
max-age指令指定从当前请求开始,允许获取的响应被重用的最长时间单位为秒。例如Cache-Control:max-age=30表示响应可以再缓存和重用 30 秒。注意,在max-age指定的时间之内,浏览器不会向服务器发送任何请求,包括验证缓存是否有效的请求,也就是说,如果在这段时间之内,服务器上的资源发生了变化,那么浏览器将不能得到通知,而使用老版本的资源。所以在设置缓存时间的长度时,需要慎重。
200 OK (from cache) 与 304 Not Modified 区别
200 OK (from cache) 是浏览器没有跟服务器确认,直接使用浏览器本地缓存;而 304 Not Modified 是浏览器和服务器多确认一次缓存有效性,再用浏览器的缓存。200(from cache) 速度最快,因为不需要访问远程服务器,直接使用本地缓存。304 的过程是先请求服务器,,然后服务器告诉浏览器这个资源没变,浏览器再使用本地缓存。
max-age=0是表示响应可以再缓存和重用 0 秒,max-age指令的特殊情况,下面先举例实践,再给出结论。
max-age结论
max-age>0 时,响应缓存和重用指定秒数,在指定秒数内直接使用游览器缓存的副本。
max-age<=0 时,向服务端发送HTTP请求确认,该资源是否有修改。有修改则返回200和最新资源;无修改则返回304,使用游览器缓存的副本。
no-cache
如果服务器在响应头中设置Cache-Control:no-cache,那么浏览器在使用缓存的资源之前,必须先与服务器确认上次返回的资源是否被更改,如果资源未被更改,直接使用浏览器缓存的副本,避免重新下载。这个验证之前的响应是否被修改,就是通过上面介绍的请求头If-None-match和响应头ETag来实现的。
注意,no-cache这个名字有一点误导。设置no-cache之后,并不是说浏览器就不再缓存数据,只是浏览器在使用缓存数据时,需要先确认一下资源是否跟服务器还保持一致。如果设置了no-cache,而ETag的实现没有反映出资源的变化,浏览器的缓存数据就不会更新,浏览器与服务器的每次请求连接反而降低性能。所以在服务器资源变化不频繁情况下,设置no-cache对于性能反而有所下降。
如果服务器在响应头设置Cache-Control:no-cache,那么浏览器在使用缓存的资源之前,必须先与服务器确认上次返回的资源是否被更改,如果资源未被更改,服务器返回304 Not Modified,浏览器使用本地缓存,避免重新下载资源。
no-cache/max-age=0区别
相同之处
no-cache并不是表示无缓存,而是指使用缓存一定要先经过验证;而max-age=0表示缓存到本地,只是在下次重新访问该页面时又会强制地从服务器验证资源。所以大部分情况下,这俩其实是一样的。
不同之处
当点击浏览器的前进后退按钮时,被no-cache的资源会重新加载;而被设置成max-age的读取则会从本地读取资源。当然这也需要根据浏览器实现的情况来看,某些浏览器如IE9之前的IE,并没有遵循http协议,直接统一了这两个字段的行为为no-cache。
手动刷新页面F5),浏览器会直接认为缓存已经过期可能缓存还没有过期,在请求中加上字段:Cache-Control:max-age=0,发包向服务器查询是否有文件是否有更新。
强制刷新页面Ctrl+F5),浏览器会直接忽略本地的缓存有缓存也会认为本地没有缓存,在请求中加上字段:Cache-Control:no-cache或 Pragma:no-cache,发包向服务重新拉取文件。
当然,各个浏览器对于刷新和强制刷新的实现方式也有一些区别。
no-cache/must-revalidate区别
no-cache: 告诉浏览器、缓存服务器,不管本地副本是否过期,使用资源副本前,一定要到源服务器进行副本有效性校验。
must-revalidate:告诉浏览器、缓存服务器,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验。
no-store
如果服务器在响应头设置Cache-Control:no-store,根据HTTP协议约定,浏览器和任何中继的Web代理,都不会存储这次响应的数据。当下次请求该资源时,浏览器只能重新请求服务器,重新从服务器读取资源。
如果服务器在响应中设置Cache-Control:no-store,那么浏览器和任何中继的Web代理,都不会存储这次响应的数据。当下次请求该资源时,浏览器只能重新请求服务器,重新从服务器读取资源。
public和private
如果设置Cache-Control:public,表示该响应可以在浏览器或者任何中继的Web代理中缓存,public是默认值,即Cache-Control:max-age=60等同于Cache-Control:public, max-age=60。
在服务器设置Cache-Control:private, max-age=60,表示只有用户的浏览器可以缓存private响应,不允许任何中继Web代理对其进行缓存。例如,浏览器可以缓存包含用户私人信息的 HTML 网页,但是 CDN 不能缓存。
Cache-Control策略优先级
如下图4所示,所谓的HTTP缓存控制,就是一种协议约定,通过设置不同的响应头Cache-Control来控制浏览器和Web代理对缓存的使用策略,通过设置请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag,来对缓存的有效性进行验证。
注意,当Cache-Control: no-store时,浏览器不会在请求头带ETag。

图4 Cache-Control策略优先级
清除缓存方法
最常用的办法就是修改文件的版本号,或者生成随机文件名,或者改变文件的最后修改时间。
本文总结自:简书大头8086
缓存的实现原理
1、什么是Web缓存
WEB缓存(cache)位于Web服务器和客户端之间。缓存会根据请求保存输出内容的副本,例如html页面,图片,文件, 当下一个请求来到的时候:如果是相同的URL,缓存直接使用副本响应访问 请求,而不是向源服务器再次发送请求。
HTTP协议定义了相关的消息头来使WEB缓存尽可能好的工作。
2、缓存的优点
减少相应 延迟:因为请求从缓存服务器(离客户端更近)而不是源 服务器被相应,这个过程耗时更少,让web服务器看上去相应更快。
减少网络 带宽消耗:当副本被重用时会减低客户端的带宽消耗;客 户可以节省带宽费用,控制带宽的需求的增长并更易于管理。
3、与缓存相关的HTTP扩展消息头
Expires:指示响应内容过期的时间,格林威治时间GMT
Cache-Control:更细致的控制缓存的内容
Last-Modified:响应中资源最后一次修改的时间
ETag:响应中资源的校验值,在服务器上某个时段是唯一标识的。
Date:服务器的时间
If-Modified-Since:客户端存取的该资源最后一次修改的时间,同Last-Modified。
If-None-Match:客户端存取的该资源的检验值,同ETag。
4、客户端缓存生效的常见流程
服务器收到请求时,会在200OK中回送该资源的Last-Modified和ETag头,客户端将该资源保存在cache中,并记录这两个属性。当客户端需要发送相同的请求时,会在请求中携带If-Modified-Since和If-None-Match两个头。两个头的值分别是响应中Last-Modified和ETag头的值。 服务器通过这两个头判断本地资源未发生变化,客户端不需要重新下载,返回304响应。
5、Web缓存机制
HTTP/1.1中缓存的目的是为了在很多情况下减少发送请求,同时在许多情况下可以不需要发送完整响应。前者减少了网络回路的数量;HTTP利用一个“过期(expiration)”机制来为此目的。后者减少了网络应用的带宽;HTTP用“验证(validation)”机制来为此目的。
HTTP定义了3种缓存机制:
1)Freshness:允许一个回应消息可以在源服务器不被重新检查,并且可以由服务器和客户端来控制。例如,Expires回应头给了一个文档不可用的时间。Cache-Control中的max-age标 识指明了缓存的最长时间;
2)Validation:用来检查以一个缓存的回应是否仍然可用。例如,如果一个回应有一个Last-Modified回应头,缓存能够使用If-Modified-Since来判断是否已改变,以便判断根据情况发送请求;
3)Invalidation: 在另一个请求通过缓存的时候,常常有一个副作用。例如,如果一个URL关联到一个缓存回应,但是其后跟着POST、PUT和DELETE的 请求的话,缓存就会过期。
HTTP缓存在哪里

图1 HTTP缓存在哪里
如图1所示HTTP缓存存在于浏览器和Web代理中。当然在服务器内部,也存在着各种缓存,比如本地缓存GuavaCache/Ehcache,分布式缓存Memcached/Redis等,但这不是本文要讨论的HTTP缓存。所谓的HTTP缓存控制,就是一种协议约定,通过设置不同的响应头Cache-Control来控制浏览器和Web代理对缓存的使用策略,通过设置请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag,来对缓存的有效性进行验证。
本文对请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag、响应头Cache-Control进行实践,分析这三种HTTP缓存头在浏览器和服务器的表现。
注意:由于前端和后端打印时间对象类不一样,将可能打印GMT或者CST时间,GMT比CST晚8小时。
请求头If-Modified-Since/响应头Last-Modified

图2 请求头If-Modified-Since/响应头Last-Modified交互时序图
如图2所示,请求头If-Modified-Since/响应头Last-Modified交互过程如下:
如图2红色部分所示,浏览器第一次向服务器请求资源时,服务器返回状态200和资源内容,同时在响应头Last-Modified字段标记该资源内容在服务器最后被修改时间,格式类似:Last-Modified: Wed, 02 Aug 2017 10:34:50 GMT,供下一次浏览器在请求头If-Modified-Since使用;
如图2紫色部分所示,浏览器第二次向服务器请求该资源时,根据HTTP协议规定,浏览器在请求头If-Modified-Since写入上次服务器返回的响应头Last-Modified值,向服务器询问该时间之后资源是否被修改过,格式类似:If-Modified-Since: Wed, 02 Aug 2017 10:34:50 GMT;
如图2绿色部分所示,当服务器资源文件有修改过,重新返回资源和状态码200给浏览器,同时在响应头Last-Modified字段标记该资源内容在服务器最后被修改时间;
如图2蓝色部分所示,当服务器资源内容没有被修改过,只给浏览器返回状态码304(Not Modified),不返回请求资源,浏览器根据304使用本地缓存,从而节省带宽,提高网页响应速度。
请求头If-None-Match/响应头ETag
ETag全称Entity Tag,用来标识一个Web资源,反映资源内容的变化。在具体的实现中,ETag可以是Web资源的hash值,也可以是一个服务器内部维护的版本号。

图3 请求头If-None-Match/响应头ETag交互时序图
如图3所示,请求头If-None-Match/响应头ETag交互过程如下:
如图3红色部分所示,浏览器第一次向服务器请求资源时,服务器返回状态码200和资源内容,同时在响应头ETag字段标识该资源内容,格式类似:ETag: "50b1a1d4f885c31:df4",供下一次浏览器在请求头If-None-Match使用;
如图3紫色部分所示,浏览器第二次向服务器请求该资源时,根据HTTP协议规定,浏览器在请求头If-None-Match写入上次服务器返回的响应头ETag值,与服务器的资源标识对比后判断资源是否被修改过,格式类似:If-None-Match: "50b1a1d4f885c31:df4";
如图3绿色部分所示,当服务器资源内容有修改过,给浏览器重新返回资源和状态码200,同时在响应头ETag字段标记该资源文件的实体值;
如图3蓝色部分所示,当服务器资源内容没有修改过,只给给浏览器返回状态码304(Not Modified),不返回请求资源,浏览器根据304使用本地缓存,节省带宽,提高网页访问速度。
请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag总结
Last-Modified和Etags如何帮助提高性能
服务端首先产生Last-Modified/Etag标记,并在HTTP响应头返回给客户端,服务端稍后使用它们判断页面是否已经被修改。客户端通过请求头If-Modified-Since/If-None-Match将Last-Modified/Etag标记传回给服务器,要求服务器验证其客户端缓存。过程如下:
1. 客户端请求一个页面A。
2. 服务器返回页面A,并在A加上响应头Last-Modified/ETag。
3. 客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。
4. 客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag作为请求头If-Modified-Since/If-None-Match一起传递给服务器。
5. 服务器检查If-Modified-Since/If-None-Match,判断出该页面自上次客户端请求之后还未被修改,直接返回状态码304和一个空的响应体。
Cache-Control
每个Web资源都可以通过HTTP响应头Cache-Control定义自己的缓存策略,Cache-Control控制谁在什么条件下可以缓存响应以及可以缓存多久。最快的请求是不必与服务器进行通信:通过响应的本地副本,我们可以避免所有的网络延迟以及数据传输的成本。为此,HTTP规范允许服务器返回一系列不同的Cache-Control指令,控制浏览器或者其他中继代理缓存如何缓存某个响应以及缓存多长时间。Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。各个消息中的指令含义如下:
Public指示响应可被任何缓存区缓存。
Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache指示请求或响应消息不能缓存。
no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
Cache-Control响应头在 HTTP/1.1规范中定义,当前的所有浏览器都支持 Cache-Control,取代了之前用来定义响应缓存策略的头例如 Expires。Cache-Control常用的指令包括如下四个,下面将对这四个指令进行详细说明。
max-age
no-cache
no-store
public/private
max-age
max-age指令指定从当前请求开始,允许获取的响应被重用的最长时间单位为秒。例如Cache-Control:max-age=30表示响应可以再缓存和重用 30 秒。注意,在max-age指定的时间之内,浏览器不会向服务器发送任何请求,包括验证缓存是否有效的请求,也就是说,如果在这段时间之内,服务器上的资源发生了变化,那么浏览器将不能得到通知,而使用老版本的资源。所以在设置缓存时间的长度时,需要慎重。
200 OK (from cache) 与 304 Not Modified 区别
200 OK (from cache) 是浏览器没有跟服务器确认,直接使用浏览器本地缓存;而 304 Not Modified 是浏览器和服务器多确认一次缓存有效性,再用浏览器的缓存。200(from cache) 速度最快,因为不需要访问远程服务器,直接使用本地缓存。304 的过程是先请求服务器,,然后服务器告诉浏览器这个资源没变,浏览器再使用本地缓存。
max-age=0是表示响应可以再缓存和重用 0 秒,max-age指令的特殊情况,下面先举例实践,再给出结论。
max-age结论
max-age>0 时,响应缓存和重用指定秒数,在指定秒数内直接使用游览器缓存的副本。
max-age<=0 时,向服务端发送HTTP请求确认,该资源是否有修改。有修改则返回200和最新资源;无修改则返回304,使用游览器缓存的副本。
no-cache
如果服务器在响应头中设置Cache-Control:no-cache,那么浏览器在使用缓存的资源之前,必须先与服务器确认上次返回的资源是否被更改,如果资源未被更改,直接使用浏览器缓存的副本,避免重新下载。这个验证之前的响应是否被修改,就是通过上面介绍的请求头If-None-match和响应头ETag来实现的。
注意,no-cache这个名字有一点误导。设置no-cache之后,并不是说浏览器就不再缓存数据,只是浏览器在使用缓存数据时,需要先确认一下资源是否跟服务器还保持一致。如果设置了no-cache,而ETag的实现没有反映出资源的变化,浏览器的缓存数据就不会更新,浏览器与服务器的每次请求连接反而降低性能。所以在服务器资源变化不频繁情况下,设置no-cache对于性能反而有所下降。
如果服务器在响应头设置Cache-Control:no-cache,那么浏览器在使用缓存的资源之前,必须先与服务器确认上次返回的资源是否被更改,如果资源未被更改,服务器返回304 Not Modified,浏览器使用本地缓存,避免重新下载资源。
no-cache/max-age=0区别
相同之处
no-cache并不是表示无缓存,而是指使用缓存一定要先经过验证;而max-age=0表示缓存到本地,只是在下次重新访问该页面时又会强制地从服务器验证资源。所以大部分情况下,这俩其实是一样的。
不同之处
当点击浏览器的前进后退按钮时,被no-cache的资源会重新加载;而被设置成max-age的读取则会从本地读取资源。当然这也需要根据浏览器实现的情况来看,某些浏览器如IE9之前的IE,并没有遵循http协议,直接统一了这两个字段的行为为no-cache。
手动刷新页面F5),浏览器会直接认为缓存已经过期可能缓存还没有过期,在请求中加上字段:Cache-Control:max-age=0,发包向服务器查询是否有文件是否有更新。
强制刷新页面Ctrl+F5),浏览器会直接忽略本地的缓存有缓存也会认为本地没有缓存,在请求中加上字段:Cache-Control:no-cache或 Pragma:no-cache,发包向服务重新拉取文件。
当然,各个浏览器对于刷新和强制刷新的实现方式也有一些区别。
no-cache/must-revalidate区别
no-cache: 告诉浏览器、缓存服务器,不管本地副本是否过期,使用资源副本前,一定要到源服务器进行副本有效性校验。
must-revalidate:告诉浏览器、缓存服务器,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验。
no-store
如果服务器在响应头设置Cache-Control:no-store,根据HTTP协议约定,浏览器和任何中继的Web代理,都不会存储这次响应的数据。当下次请求该资源时,浏览器只能重新请求服务器,重新从服务器读取资源。
如果服务器在响应中设置Cache-Control:no-store,那么浏览器和任何中继的Web代理,都不会存储这次响应的数据。当下次请求该资源时,浏览器只能重新请求服务器,重新从服务器读取资源。
public和private
如果设置Cache-Control:public,表示该响应可以在浏览器或者任何中继的Web代理中缓存,public是默认值,即Cache-Control:max-age=60等同于Cache-Control:public, max-age=60。
在服务器设置Cache-Control:private, max-age=60,表示只有用户的浏览器可以缓存private响应,不允许任何中继Web代理对其进行缓存。例如,浏览器可以缓存包含用户私人信息的 HTML 网页,但是 CDN 不能缓存。
Cache-Control策略优先级
如下图4所示,所谓的HTTP缓存控制,就是一种协议约定,通过设置不同的响应头Cache-Control来控制浏览器和Web代理对缓存的使用策略,通过设置请求头If-Modified-Since/响应头Last-Modified、请求头If-None-Match/响应头ETag,来对缓存的有效性进行验证。
注意,当Cache-Control: no-store时,浏览器不会在请求头带ETag。

图4 Cache-Control策略优先级
清除缓存方法
最常用的办法就是修改文件的版本号,或者生成随机文件名,或者改变文件的最后修改时间。
本文总结自:简书大头8086