f5到底刷新了点什么,你知道吗
缓存从入门到放弃
强制缓存(200)和协商缓存(304)
前端HTTP 缓存简单了解
当浏览器第一次加载资源的时候,返回一般为200,意思是成功获取资源,并会在浏览器的缓存中记录下max-age,第二次访问的时候: 如果只是用浏览器打开,那么浏览器会去判断这个资源在缓存里有没有,如果有的话,会去判断max-age,看看过期没有,如果没有过期,则直接读缓存,根本不会和服务器进行交互,换句话说,断网都能打开,就和本地跑一样!如果已经过期了,那就去服务器请求,等待服务器响应,这是很费时间的,服务器如果发现资源没有改变过,那么就会返回304,告诉浏览器,我没变过,你去读缓存吧,于是浏览器也不用从服务器拉数据了,然而,等待服务器响应也是一个很要命的问题,在网速发达的今天,等一个响应,有时比下载还慢。 如果是用浏览器刷新的,那么浏览器不会去判断max-age了,直接去服务器拿,如果服务器判断资源没变过,则还是会返回304,和上面是一样的,所以刷新一下,其实很可怕,等于把所有的资源都要去服务器请求一边,问问服务器我过期了没有。
浏览器在第一次请求资源的时候,服务端响应头里可以设置expires字段,该字段表示该资源的缓存过期时间,第二次请求的时候,如果时间还在该缓存时间之内,则会直接使用缓存,否则重新加载资源, 这个expires字段有个缺陷,就是它必须服务端和客户端的时间严格同步才能生效,所以现在很多人不会使用改方案。 另外一种方案是第一次请求资源的时候,服务端设置响应头cache-control: max-age,这样设置的意思是告诉浏览器,这个资源什么时候过期,等第二次请求资源的时候,判断是否超出了过期时间,如果没超出,直接使用缓存。
记一次前端面试的全过程
缓存状态码 200 OK (from cache) 与 304 Not Modified
200 OK (from cache) 是浏览器没有跟服务器确认,直接用了浏览器缓存;
304 Not Modified 是浏览器和服务器多确认了一次缓存有效性,再用的缓存。
304 Not Modified:客户端有缓冲的文件并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
304 Not Modified 比 200 OK (from cache) 慢,指的是浏览器还向服务器确认了下 “If-Not-Modified”,才用的缓存
参考http 200、301、304等状态码详解
200和304特点
状态码200:请求已成功,请求所希望的响应头或数据体将随此响应返回。即返回的数据为全量的数据,如果文件不通过GZIP压缩的话,文件是多大,则要有多大传输量。
状态为304的请求要比状态为200的请求的数据量小很多,因为304只需要返回响应头,并不需要返回整个文件,所以只需要几字节就可以了,这样能够节省大量的网络带宽,并减少了页面的渲染时间。状态码304:如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。即客户端和服务器端只需要传输很少的数据量来做文件的校验,如果文件没有修改过,则不需要返回全量的数据。
缓存HTTP头信息
Date:原服务器发送该资源响应报文的时间(GMT格式)
Age:Age表示这个响应已经存活了多久了(HTTP/1.0的响应不带Age)
Expires:即在 HTTP 头中指明具体失效的时间(HTTP/1.0),Expires = HTTP-date
Pragma:no-cache,每次请求页面时都不要读缓存,兼容HTTP/1.0,优先级高于Expires(HTTP/1.0 + HTTP/1.1)
Cache Control:优先级高于Pragma、Expires(HTTP/1.1) 【public,客户端和服务端都可以缓存;private,只能客户端缓存;no-store,不使用缓存;no-cache,使用协商缓存。】
Expires
- Expires是http1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回。
- Expires第二次请求时,将和本地时间比对。
Expires 第一次请求服务器是,响应头会返回一个Expires的文件过期时间。
Expires 第二次请求,客户端使用本地时间和文件的过期时间进行比对,如果文件未过期则直接使用本地缓存,返回状态码200(from memory cache)或200(from disk cache)。
Expires Cache-Control
- Cache-Control: no-cache 必须先与代理服务器确认是否更改,然后在在决定使用缓存还是请求,类似于协商缓存(304)
- Cache-Control: no-store 才是真正的不缓存数据到本地
- Cache-Control: public 可以被所有用户缓存(多用户共享),包括终端和CDN等中间代理服务器
- Cache-Control: private 只能被终端浏览器缓存(而且是私有缓存),不允许中继缓存服务器进行缓存
- Cache-Control: must-revalidate如果缓存内容失效,请求必须发送服务器进行验证
- Cache-Control: max-age=s 缓存内容在s秒后失效,仅HTTP1.1可用
max-gae 第一次请求服务器时,响应头会返回一个 max-age,是文件多少时间后过期。
max-gae 第二次请求,客户端会校验文件是否过期,如果文件未过期则直接使用本地缓存,返回状态码200(from memory cache)或200(from disk cache)。
本地缓存,是指在客户端本地机器中的缓存。
共享缓存,处于客户端和服务器之间的缓存,例如:CDN。
请求 Cache Control
– | – |
---|---|
max-age | 可以接收缓存最长时间 |
max-stale | 可以接收过期的资源,但是过期时间必须小于 max-stale 值 |
min-fresh | 可以接收一个更新过的资源,fresh生命期大于其当前 Age 跟 min-fresh 值之和 |
no-cache | 在源服务器返回成功的验证之前不能使用缓存响应 |
no-store | 直接禁止浏览器和所有中继缓存存储返回的任何版本的响应 |
no-transform | 获取没有被转换过(比如压缩)的资源 |
only-if-cached | 希望获取缓存内容而不发起请求 |
响应 Cache Control
– | – |
---|---|
no-cache | 缓存必须重新校验 |
no-store | 不存储缓存 |
no-transform | 缓存内容时不能对改变任何数据 |
public | 响应可被任何缓存区缓存 |
private | 只在本地缓存,不允许任何中继缓存对其进行缓存(例如,浏览器可以缓存,但是CDN不能缓存) |
must-revalidate | 如果缓存的内容失效,请求必须发送到服务器以进行重新验证(请求失败返回504,而非中间缓存CDN) |
proxy-revalidate | 与must-revalidate类似,仅能用于共享缓存(如:CDN) |
max-age | 只接受 Age 值小于 max-age 值,并且没有过期的资源 |
s-maxage | 仅能用于共享缓存,一般用在cache服务器上(如:CDN) |
Cache Control Extensions
通过使用1个或多个cache-extension tokens扩展(可选)字段,服务器不识别则忽略掉1
Cache-Control:private, community="UCI"
Cache-Control 允许自由组合可选值1
Cache-Control: max-age=3600, must-revalidate
Last-Modified/If-Modified-Since:文件最后一次修改的时间(精度是秒,HTTP/1.0),需要Cache-Contral过期
Etag:当前资源在服务器的唯一标识(生成规则由服务器决定)ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的,优先级高于Last-Modified;在分布式的Web系统中,当访问落在不同的物理机上时会返回不同的ETag,进而导致304失效,降级为200请求(HTTP/1.1),需要Cache-Contral过期
如果 Last-Modified 和 ETag 同时被使用,则要求它们的验证都必须通过才会返回304,否则返回200。
Meta标签
meta是用来在HTML文档中模拟HTTP协议的响应头报文。在HTML页面加上meta标签来给请求报头加上请求字段。1
2
3<meta http-equiv="Expires"content="0">
<meta http-equiv="Pragma"content="no-cache">
<meta http-equiv="Cache-Control"content="no-cache">
Pragma的meta标签只有IE能识别
“Pragma:No-cache”标记可能无法防止页面被缓存
优先级:Cache-Control > Pragma > Expires
清除浏览器中的缓存,必须从服务端获取最新内容,但不是所有浏览器都支持
缓存机制
Freshness
和浏览器策略以及Cache Control(HTTP/1.1)与Expires(HTTP/1.0)有关
最好的请求是不必与服务器进行通信的请求:通过响应的本地缓存,可以避免所有的网络延迟以及数据传输的数据成本。
服务器给响应设置显示过期时间(explicit expiration time),当请求资源时,只需要检测资源的过期状态,判断是否使用缓存。
服务器不提供一个显示过期时间,HTTP缓存通常会设置一个启发式过期时间(heuristic expiration time),采用算法通过其他值(例如Last-Modified)估计一个合理的时间。
如何判断响应是否新的?1
response_is_fresh =(freshness_lifetime > current_age)
freshness_lifetime计算,同时存在多个,按优先级获取
如果是共享缓存,使用s-maxage
如果有max-age字段,使用max-age
如果有Expires字段,使用Expires超过Date的时间数
如果没有显示过期时间设置,使用浏览器的启发式过期时间(heuristic expiration time)
current_age计算
age_value Age字段的值
date_value Date字段的值
now 当前时间
request_time 请求时间
response_time 响应时间
1 | apparent_age = max(0, response_time - date_value); |
缓存策略
HTML5 Boilerplate 项目nginx配置文件样例
1 | # cache.appcache, your document html and data |
Validation
检查一个缓存的响应是否仍然可用 Last-Modified和ETag(entity-tag)
通过验证令牌可以进行高效的资源更新检查:如果资源未更改,则不会传输任何数据1
2
3
4
5
6
7Status Code:304 Not Modified
Response Head
ETag:"578ba64c-7ddf"
Last-Modified:Sun, 17 Jul 2016 15:37:48 GMT
Request Head
If-Modified-Since:Sun, 17 Jul 2016 15:37:48 GMT
If-None-Match:"578ba64c-7ddf"
Invalidation
类似PUT、POST 和 DELETE的”非安全”请求可能会改变原服务端状态,在此期间缓存会让它们的内容过期失效。
当一个非安全的请求收到非错误的返回状态码(2xx或者3xx),缓存必须使请求URI的包括其他相关URI(s)的Location和Content-Location响应头字段失效。
为了防止服务器攻击拒绝,一个基于Location或Content-Location头域里的URI的无效性处理必须只有在host部分和请求URI里的host部分相同时才被执行。
注:只读请求(GET/HEAD)认为是“安全”的,详细可查看safe.methods。
200 or 304
在没有设置Cache-Contral的情况下,设置Last-Modified和ETag缓存,会出现时而200(from cache),时而304 出现的情况。
chrome 测试 刷新 和 输入URL回车 测试并不会影响200(from cache)和304 的出现。
可能的情况,是在服务器没有设置显示缓存时间的情况下,freshness_lifetime是浏览器按某种算法计算出来,这个时间并不长,所以会出现这种情况。
设置Cache-Contral max-age的情况下,max-age过期后首次刷新会出现304(如果有更新内容,则是200),之后在max-age缓存过期之前刷新都是200(from cache)。
缓存方案
较长的过期时间,节省带宽,提高性能;更改资源的网址,强制用户下载新响应
按需更新,精确的缓存控制
静态资源CDN部署
更资源发布路径实现非覆盖式发布(多版本共存)