http 缓存
强缓存和协商缓
- 共同点:都是从客户端缓存中读取资源
- 强缓存不会发送请求,
- 协商缓存会发送请求
相关状态码
- 302 临时重定向
- 304 走的浏览器缓存
强缓存
- 不会向服务器发送请求,直接从缓存中读取资源,在Chrome控制台的Network选项中,
协商缓存
- 向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源
相关header
强缓存
- Expires: response header里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存
- Cache-Control: 当值为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存
- pragma: 不直接使用缓存,根据新鲜度来使用缓存,Http1.1中已经废弃,响应头不支持这个属性,为了兼容1.0
- 区别:
- Expires是http1.0的产物,Cache-Control是http1.1的产物,两者同时存在的话,Cache-Control优先级高于Expires
- Expires其实是过时的产物,现阶段存在知识一种兼容的写法
- Pragma和Cache-control共存时,Pragma的优先级是比Cache-Control高的
协商缓存
- ETag和If-None-Match:
- Etag是上一次加载资源时,服务器返回的response header,是对该资源的一种标识,只要资源有变化,Etag就会重新生成
- 浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的Etag值放到request header里的If-None-Match里
- 服务器接受到If-None-Match的值后,会拿来改资源文件的Etag值做比较,如果相同,则表示资源文件没有发生改变,命中协商缓存
- Last-Modified和If-None-Modified-Since
- Last-Modified是该资源文件最后一次更改时间,服务器会在response header里返回
- 浏览器会将这个值保存起来,下一次发送请求时,放到request header里的If-Modified-Since里
- 服务器就收到后做对比,如果相同则命中协商缓存
- 在精确度上,Etag要优于Last-Modified,Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度
- 在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。
- 在优先级上,服务器校验优先考虑Etag。所以两者互补
- 强缓存和协商缓存:最好是配合在一起使用,争取最大化的减少请求,利用缓存,节约流量
浏览器缓存过程
- 浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并把response header及该请求的返回时间(要与Cache-Control和Expires对比)一并缓存
- 下一次加载资源时,先比较当前时间和上一次返回200时的时间差,如果没有超过Cache-Control设置的max-age,则没有过期,命中强缓存,不发送直接从本地缓存读取文件(如果浏览器不支持1.1,则用Expires判断是否过期)
- 如果时间过期,服务器则查看header里的If-None-Match和If-Modified-Since
- 服务器优先根据Etag的值判断被请求的文件有没有做修改,Etag值一致则没有修改,命中协商缓存,返回304;如果不一致则有改动,直接返回新的资源带上新的Etag值并返回200
- 如果服务器收到的请求没有Etag值,则将If-Modified-Since和被请求文件的最后修改时间做比对,一致泽明中协商缓存,返回304;不一致则返回新的last-modified和文件并返回200
使用http缓存的好处
- 减少冗余的数据传输,节省网费
- 缓解了服务器压力,提高网站的性能
- 加快了客户端加载网页的速度
用户行为对浏览器缓存的控制
- 地址栏访问
- 链接跳转是正常用户行为,将会触发浏览器缓存机制
- 浏览器发起请求-->按照正常流程-->本地检查是否过期-->或者服务器检查新鲜度-->最后返回内容
- F5刷新
- 浏览器设置max-age = 0跳过强缓存判断,会进行协商缓存判断
- 浏览器直接对本地缓存文件过期,但是会带上If-Modified-Since,If-None-Match(如果上一次response带Last-Modified,Etag)
- 服务器会对文件检查新鲜度,返回结果可能是304,也可能是200
- Ctrl + F5 强制刷新
- 跳过强缓存和协商缓存,直接从服务器拉取资源
- 浏览器不仅会对本地文件过期,而且不会带上If-Modified-Since,If-None-Match,相当于之前从来没有请求过,返回结果是200
如何设置不缓存
- Cache-Control其他字段
- no-cache:仍然是对资源使用缓存,但每一次在使用缓存之前必须像服务器对缓存资源进行验证
- no-store: 不适用任何缓存
- 禁止缓存:
Cache-Control: no-cache,no-store,must-revalidate
- Expires: 设为当前时间之前
前端开发设置不缓存
- 引用js、css文件的URL后面加上随机数或时间戳
<script type=“text/javascript” src=“/js/test.js?+Math.random()”></script>
- 设置HTML页面不让浏览器缓存的方法
<meta http-equiv="pragma" content="no-cache">
// 仅有IE浏览器才识别的标签,不一定会在请求字段加上Pragma,但的确会让当前页面每次都发新请求
<meta http-equiv="Cache-Control" content="no-cache, must-revalidate">
// 其他主流浏览器识别的标签
<meta http-equiv="expires" content="Wed, 26 Feb 1997 00:00:00 GMT">
// 仅有IE浏览器才识别的标签,该方式仅仅作为知会IE缓存时间的标记,你并不能在请求或响应报文中找到Expires字段
- content属性:
- public:表示可以在任何客户端(包括本地缓存、浏览器、各种代理服务器等等)中缓存,但不能设置缓存期限;
- max-age=秒数:表示不仅可以被任何客户端缓存,还可以设置缓存期限,是相对服务器时间而言的
<meta http-equiv="Cache-Control" content="max-age=60"/> - private:只能被单个用户缓存,不允许任何中间代理进行缓存(即各种代理服务器不能缓存,比如,CDN不能缓存private的响应);
- only-if-cached:表明如果缓存存在,只使用缓存,不需要请求服务器加载更新内容。
- no-cache: 先发送请求,与服务器确认该资源是否被更改,如果未被更改,则使用缓存。
- no-store:不允许缓存,再次访问页面需要重新从服务器上加载缓存;
- no-transform:不得对网页内容或网页中的资源进行转换或转变,以便节省缓存空间或者减少缓慢链路上的流量。
- no-siteapp:表示禁止百度、神马、搜狗等移动搜索引擎对网页进行转码处理
在chrome浏览器中返回的200状态会有两种情况:
-
from memory cache (从内存中获取/一般缓存更新频率较高的js、图片、字体等资源)
-
from disk cache (从磁盘中获取/一般缓存更新频率较低的js、css等资源)
-
这两种情况是chrome自身的一种缓存策略,这也是为什么chrome浏览器响应的快的原因。其他浏览返回的是已缓存状态,没有标识是从哪获取的缓存。