Http缓存
-
缓存控制:控制缓存的开关,用于标识请求或访问中是否开启了缓存,使用了哪种缓存方式。
-
缓存校验:如果缓存控制开关打开,如何校验缓存,比如怎么定义缓存的有效期,怎么确保缓存是最新的。
缓存控制
1. Expires
2. Cache-Control
3. Pragma
Expires
Expires 响应头包含日期/时间, 即在此时候之后,响应过期。
Expires因为是对时间设定的,且时间是Greenwich Mean Time (GMT),而不是本地时间,所以对时间要求较高。
Response Header
Expires: Wed, 21 Oct 2020 17:28:00 GMT
Cache-control
Cache-Control 通用消息头字段,被用于在http请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。
指令不区分大小写,并且具有可选参数,可以用令牌或者带引号的字符串语法。多个指令以逗号分隔。
缓存请求指令
客户端可以在HTTP请求中使用的标准 Cache-Control 指令。
Request Header
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached
缓存响应指令
服务器可以在响应中使用的标准 Cache-Control 指令。
Response Header
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=<seconds>
Cache-Control: s-maxage=<seconds>
Cache-control的值可以按以下性质分类
1.可缓存性、控制开关
- 否可以缓存,以及是私有还是共享缓存
public
表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容。(例如:1.该响应没有max-age指令或Expires消息头;2. 该响应对应的请求方法是 POST 。)
private
表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。私有缓存可以缓存响应内容,比如:对应用户的本地浏览器。
no-cache
在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证(协商缓存验证)。
no-store
缓存不应存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。
2. 缓存到期
max-age=
设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。
s-maxage=
覆盖max-age或者Expires头,但是仅适用于共享缓存(比如各个代理),私有缓存会忽略它。
max-stale[=]
表明客户端愿意接收一个已经过期的资源。可以设置一个可选的秒数,表示响应不能已经过时超过该给定的时间。
min-fresh=
表示客户端希望获取一个能在指定的秒数内保持其最新状态的响应。
3.重新验证和重新加载
must-revalidate
一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。
proxy-revalidate
与must-revalidate作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。
4.其他
no-transform
不得对资源进行转换或转变。Content-Encoding、Content-Range、Content-Type等HTTP头不能由代理修改。例如,非透明代理或者如Google’s Light Mode可能对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。no-transform指令不允许这样做。
only-if-cached
表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝。
Cache-Control缓存策略
HTTP/1.1定义的 Cache-Control 头用来区分对缓存机制的支持情况, 请求头和响应头都支持这个属性。通过它提供的不同的值来定义缓存策略。
1.没有缓存
缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。
Request Header
Cache-Control: no-store
表示客户端不希望这个请求的响应进行任何缓存
Response Header
Cache-Control: no-store
表示服务端不希望对个资源进行任何缓存
2.缓存但重新验证
如下头部定义,此方式下,每次有请求发出时,缓存会将此请求发到服务器,服务器端会验证请求中所描述的缓存是否过期,若未过期(注:实际就是返回304),则缓存才使用本地缓存副本。
Request Header
Cache-Control: no-cache
表示客户端希望用协商缓存的方式进行缓存
Response Header
Cache-Control: no-cache
表示服务端希望用协商缓存的方式进行缓存
3.私有和公共缓存
“public” 指令表示该响应可以被任何中间人(比如中间代理、CDN等)缓存。若指定了"public",则一些通常不被中间人缓存的页面(因为默认是private)(比如 带有HTTP验证信息(帐号密码)的页面 或 某些特定状态码的页面),将会被其缓存。
“private” 则表示该响应是专用于某单个用户的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。
Response Header
Cache-Control: private
or
Cache-Control: public
可以结合协商缓存
Cache-Control: public,no-cache
Cache-Control: private,no-cache
4.强缓存
过期机制中,最重要的指令是 “max-age=”,表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改变的文件,通常可以手动设置一定的时长以保证缓存有效,例如图片、css、js等静态资源。
Request Header
Cache-Control: max-age=31536000
配合Age请求头 来表示客户端缓存资源是否到期
Cache-Control: max-age=31536000
Age: 10
Response Header
Cache-Control: max-age=31536000
可以结合私有和公共缓存
私有强缓存
Cache-Control: private,max-age=31536000
公共强缓存
Cache-Control: public,max-age=31536000
表示服务端当前资源如果做缓存后可用的时间
5.验证方式
当使用了 “must-revalidate” 指令,那就意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。
Response Header
Cache-Control: must-revalidate
表示服务端希望客户端进行验证
Cache-control --VS-- Expires
Cache-control内容要远比Expires复杂的多,也是本文重点。
-
Expires
是HTTP1.0协议中用来控制缓存的http头,Cache-Control
是HTTP1.1协议新版的API。现在首选Cache-Control
。如果在Cache-Control
响应头设置了 “max-age” 或者 “s-max-age” 指令,那么Expires
响应头会被忽略。 -
HTTP1.1协议中的,因为有了
Cache-control
,所以可以忽略上面提到的Expires
。因为Cache-Control
相对于Expires
更加具体,细致。
且,就算同时设置了Cache-Control
和Expires
,Cache-Control
的优先级也高于Expires
。
Pragma
Pragma
是一个在 HTTP/1.0 中规定的通用首部,这个首部的效果依赖于不同的实现,所以在“请求-响应”链中可能会有不同的效果。它用来向后兼容只支持 HTTP/1.0 协议的缓存服务器,那时候 HTTP/1.1 协议中的Cache-Control
还没有出来。
Cache-Control: no-cache
Pragma: no-cache
**注意:**由于 Pragma 在 HTTP 响应中的行为没有确切规范,所以不能可靠替代 HTTP/1.1 中通用首部 Cache-Control,尽管在请求中,假如 Cache-Control 不存在的话,它的行为与 Cache-Control: no-cache 一致。建议只在需要兼容 HTTP/1.0 客户端的场合下应用 Pragma 首部。
缓存的两种形式
-
强缓存:浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-control和expires信息),若命中直接从缓存中获取资源信息,包括缓存header信息;本次请求根本就不会与服务器进行通讯
-
协商缓存:若是没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/If-Modified-Since和Etag/If-None-Match),由服务器根据请求中的相关header信息来比对结果是否协商缓存命中;若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,可是并不返回资源内容,它会告知浏览器能够直接从缓存获取;不然返回最新的资源内容
缓存校验
当缓存控制采用
Cache-Control: no-cache
Cache-Control: max-age=0
Cache-Control: must-revalidate
以上等情况时表示,表示使用协商缓存的方式
响应头ETag —对应— 请求头If-None-Match
响应头Last-Modified —对应— 请求头If-Modified-Since
ETag
作为缓存的一种强校验器,
ETag
响应头是一个对用户代理(User Agent
, 下面简称UA)不透明的值。对于像浏览器这样的HTTP UA,不知道ETag
代表什么,不能预测它的值是多少。如果资源请求的响应头里含有ETag
, 客户端可以在后续的请求的头中带上If-None-Match
头来验证缓存。
Reqsponse Header
ETag: "3e86-410-3596fbbc"
If-None-Match
If-None-Match
是一个条件式请求首部。对于 GET 和 HEAD 请求方法来说,当且仅当服务器上没有任何资源的ETag
属性值与这个首部中列出的相匹配的时候,服务器端会才返回所请求的资源,响应码为200。对于其他方法来说,当且仅当最终确认没有已存在的资源的ETag
属性值与这个首部中所列出的相匹配的时候,才会对请求进行相应的处理。
Request Header
If-None-Match: "3e86-410-3596fbbc"
一般ETag的值是资源的MD5值,由服务端开发人员在响应头中返回,当客户端再次发起相同的请求时,请求头中添加If-None-Match
If-None-Match: "3e86-410-3596fbbc"
服务端人员可以通过下面的伪代码来判断如何进行返回
if(request.header("If-None-Match") == "3e86-410-3596fbbc")
{
response.statuscode = 304;
}
else
{
response.write(string);
}
If-None-Match:告诉服务器如果一致,返回状态码304,不一致则返回资源。
Last-Modified
Last-Modified
响应头可以作为一种弱校验器。说它弱是因为它只能精确到一秒。如果响应头里含有这个信息,客户端可以在后续的请求中带上If-Modified-Since
来验证缓存。
Reponse Header
Last-Modified 文件最后修改时间 秒级别
Last-Modified: Thu, 03 Jul 2018 00:00:00 GMT
If-Modified-Since
If-Modified-Since 是一个条件式请求首部,服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 。如果请求的资源从那时起未经修改,那么返回一个不带有消息主体的 304 响应,而在 Last-Modified 首部中会带有上次修改时间。 不同于 If-Unmodified-Since, If-Modified-Since 只可以用在 GET 或 HEAD 请求中。
当与 If-None-Match 一同出现时,它(If-Modified-Since)会被忽略掉,除非服务器不支持 If-None-Match。
Request Header
If-Modified-Since: Thu, 03 Jul 2018 00:00:00 GMT
如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。
如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。
从这个GMT指定时间开始 未修改过
请求网站的时间
Date: Tue, 11 Jul 2000 18:23:51GMT
参考文献