标签:方式 标识符 font http 信息 long 缓存策略 忽略 特性
浏览器的缓存可分为HTTP缓存和离线缓存,下面将分别介绍
只有GET请求能被缓存,POST不能被缓存。
Modified Time/ETag/Expires/Cache都是HTTP协议的缓存策略
当我们第二次访问百度首页,在Chrome的Network面板中打开一个静态文件时会发现响应的status是:200 OK (from disk cache),不是应该返回304 Not Modified吗?如果你知道答案,那就可以忽略本文了。
w3.org 的定义是:“The Cache-Control general-header field is used to specify directives which MUST be obeyed by all caching mechanisms along the request/response chain.”
这是一个通用首部字段(就是请求报文和响应报文都能用上的字段),用来控制HTTP缓存的行为。
例如:
Cache-Control: max-age=3600, publicpublic
意味着这个响应可以被任何人缓存max-age
则表明了该缓存有效的秒数,允许你的网站被缓存将大大减少下载时间和带宽,同时也提高浏览器的载入速度。
也可以通过设置no-cache
指令来禁止缓存:
Cache-Control: no-cache
Cache-Control也是一个通用首部字段,这意味着它能分别在请求报文和响应报文中使用。在RFC中规范了Cache-Control 的格式为:Cache-Control: cache-directive
作为请求首部时,cache-directive 的可选值有:
当请求头中有:Cache-Control: max-age=0,表示缓存需要进行验证(ETag||Last-Modified),如果缓存未过期,则可以使用。
当请求头中有:Cache-Control: no-cache,表示浏览器只能获取最新的文件。 和Response Header中的no-store相对应。
作为响应首部时,cache-directive 的可选值有:
public: 共有缓存,可被缓存代理服务器缓存,比如CDN
private: 私有缓存,不能被共有缓存代理服务器缓存,可被用户的代理缓存如浏览器。
max-age=[秒]:表示在这个时间范围内缓存是新鲜的无需更新。类似Expires时间,不过这个时间是相对的,而不是绝对的。也就是某次请求成功后多少秒内缓存是新鲜的。
s-maxage=[秒]:类似max-age, 除了仅应用于共享缓存(如代理)。
no-cache:这里不是不缓存的意思,只是每次在使用缓存之前都强制发送请求给源服务器进行验证,检查文件该没改变(其实这里和ETag/Last区别不大)
no-store:就是禁止缓存,不让浏览器保留缓存副本
must-revalidate:告诉浏览器,你这必须再次验证检查信息是否过期, 返回的代号就不是200而是304了。
proxy-revalidate:类似must-revalidate,除了只能应用于代理缓存。
no-cache等同于max-age=0
Cache-Control 允许自由组合可选值,例如:Cache-Control: max-age=3600, must-revalidate
这意味着该资源是从原服务器上取得的,且其缓存(新鲜度)的有效时间为一小时,在后续一小时内,用户重新访问该资源时无须发送请求。
Cache-Control字段能让客户端决定是否向服务器发送请求,比如设置的缓存时间未过期,那么自然直接从本地缓存取数据即可(在chrome下表现为200 from cache),若缓存时间过期了或资源不该直接走缓存,则会发请求到服务器去。
我们现在要说的问题是,如果客户端向服务器发了请求,那么是否意味着一定要读取回该资源的整个实体内容呢?
我们试着这么想——客户端上某个资源保存的缓存时间过期了,但这时候其实服务器并没有更新过这个资源,如果这个资源数据量很大,客户端要求服务器再把这个东西重新发一遍过来,是否非常浪费带宽和时间呢?
答案是肯定的,那么是否有办法让服务器知道客户端现在存有的缓存文件,其实跟自己所有的文件是一致的,然后直接告诉客户端说这东西你直接用缓存里的就可以了,我这边没更新过呢,就不再传一次过去了
。
为了让客户端与服务器之间能实现缓存文件是否更新的验证、提升缓存的复用率,HTTP定义了以下两种校验方法。
请求首部字段
响应首部字段
服务器将资源传递给客户端时,会将资源最后更改的时间以Last-Modified: GMT
的形式加在实体首部上一起返回给客户端。
客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求报文中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回304状态码即可。
请求首部字段
响应首部字段
服务器会通过某种算法,给资源计算得出一个唯一标志符(比如md5标志
),在把资源响应给客户端的时候,会在实体首部加上ETag: 唯一标识符
一起返回给客户端。
客户端会保留该 ETag 字段,并在下一次请求时将其一并带过去给服务器。服务器只需要比较客户端传来的ETag跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。
如果服务器发现ETag匹配不上,那么直接以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端;如果ETag是一致的,则直接返回304知会客户端直接使用本地缓存即可。
使用 Expires 来兼容旧的浏览器,使用Cache-Control来更精准地利用缓存,分类管理:HTML, JS, CSS, Photo, Fonts,然后开启 ETag 跟 Last-Modified 功能(在较新的 nginx 上默认是同时开启了这两个功能的)进一步复用缓存减少流量。腾讯首页是60s的缓存。而静态资源则会设置一个较长的时间。
无法获取静态资源:在文件名或参数带上一串md5或时间标记符。
现在回过头来看文章开头的问题,可能会觉得答案很容易回答出来。
百度首页的资源在刷新后实际没有发送任何请求,因为 Cache-Control 定义的缓存时间段还没到期
。在Chrome中即使没发送请求,但只要从本地的缓存中取,都会在Network面板显示一条状态为200且注明from cache
的伪请求,其Response内容只是上一次留下的数据。
当下大多数浏览器在点击刷新按钮或按F5时会强行给请求加上Cache-Control:max-age=0
请求字段,所以这里提及的刷新指的是选中url地址栏并按回车键(这样不会被强行加上Cache-Control)
。
在这里简单介绍一下serviceWorker,其和webWorker一样都是一种运行在浏览器中的后台线程,只不过它的权限更大,可以拦截HTTP请求
,通过编程的方式去控制HTTP缓存(HTTP缓存在JS中是全局对象caches,其类型为cacheStorage
),所以只有https站点才可以使用service worker,当然localhost是一个特例。
另外serviceWorker完全遵循fetch
的API。
离线缓存的应用场景是当APP没有网络时,也可以正常进行相关操作,在JS中是全局对象applicationCache
。
请尽量不要使用该特性,其已经从Web标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请改用Service Workers代替。但Service Workers属于实验性质的技术,caniuse 上面显示chrome49+ firefox58+,IE系列全部不支持,属于不兼容的新技术,先保持观望。
浅谈浏览器http的缓存机制
Service Worker初体验
MDN Service Worker
Service Worker最佳实践
JavaScript中的cacheStorage使用详解
HTTP Get,Post请求详解
原文:大专栏 浅谈浏览器的缓存机制
标签:方式 标识符 font http 信息 long 缓存策略 忽略 特性
原文地址:https://www.cnblogs.com/peterchan1/p/11640697.html