本文作者:IMWeb 存勖闲 原文出处:IMWeb社区
原文链接:http://www./index.php/2018/12/26/浏览器缓存/ 今天我们来说一下浏览器缓存的问题,缓存可以减少网络IO的消耗,提高访问速度。浏览器缓存是一种操作简单、效果显著的前端性能优化手段。 关于缓存的头部字段包括: cache-control(缓存头)可缓存性public :
即使它有相关联的http身份验证,甚至响应状态代码通常无法缓存,也可以缓存响应。大多数情况下,public 不是必需的,因为明确的缓存信息(例如max-age )已表示响应是可以缓存的。
private :
浏览器可以缓存private 响应。不过,这些响应通常只为单个用户缓存,因此不允许任何中间缓存对其进行缓存。例如,用户的浏览器可以缓存包含私人信息的HTML网页,但CDN却不能进行缓存。
no-cache :
表示必须先与服务器确认返回的响应是否发生了变化,然后才能使用该响应来满足后续对同一网址的请求。因此,如果存在合适的验证令牌(Etag ),no-cache 会发起往返通信来验证缓存的响应,但如果资源未发生变化,则可避免下载。有的时候只设置no-cache 防止缓存还是不够保险,还可以加上private 指令,将过期时间设为过去的时间。
到期max-age=(seconds )
指令指定从请求的时间开始,允许获取的响应被重用的最长时间(单位:秒)。例如,"max-age=60 "表示可在接下来的60秒缓存和重用响应。 s-maxage=(seconds ):同max-age ,只用于共享缓存(比如CDN缓存)
比如,当s-maxage=60 时,在这60秒钟,即使更新了CDN的内容,浏览器也不会进行请求。也就是说max-age用与普通缓存,而s-maxage 用于代理缓存,如果存在s-maxage ,则会覆盖掉max-age 和Expires header。 max-stale=(seconds )
为发起端设置,即使缓存已经到期,但在max-stale 设置的时间内还可以使用过期的缓存。 重新验证must-revalidate 缓存必须在使用之前验证旧资源的状态,并且不可使用过期资源。
proxy-revalidate 与must-revalidate 作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。
其他no-store 直接禁止浏览器以及所有中间缓存存储任何版本的返回响应,例如,包含个人隐私数据或银行业务数据的响应。每次用户请求该资源时,都会向服务器发送请求,并下载完整的响应。
no-transform 不得对资源进行转换或转变。Content-Encoding, Content-Range, Content-Type等HTTP头不能由代理修改。例如,非透明代理可以对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。 no-transform指令不允许这样做。
Pragma当该字段值为no-cache 的时候。会告诉浏览器不要对该资源缓存,及每一次都得向服务器发送一次响应。 res.serHeader('Pragma','no-cache') //禁止缓存
res.setHeader('Cache-Control','public,max-age=120') //2分钟
通过Pragma 来禁止缓存,通过Cache-Control 设置两分钟缓存,但是重新访问我们会发现浏览器会再次发起一次请求,说明了Pragma的优先级高于Cache-Control 。 Expires缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires = max-age + 请求时间 ,需要和Last-modified 结合使用。但在上面我们提到过,cache-control 的优先级更高。Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前可以直接从浏览器缓存取数据,而无需再次请求。 Last-Modified 上次修改时间服务器端文件的最后修改时间,需要和catch-control 共同使用,是检查服务器资源是否更新的一种方式。当浏览器再次进行请求时,会向服务器传送If-Modified-Since 报头,询问Last-Modified 时间点之后资源是否被修改过。如果没有修改,则返回码为304,使用缓存;如果修改过,则再次去服务器请求资源,返回码和首次请求相同为200,资源为服务器最新资源。 Etag 数据签名根据试题内容生成一段哈希字符串,标识资源的状态,由服务器产生。浏览器会将这串字符串传回服务器,验证资源是否已被修改,如果没有修改,过程如下:使用Etag可以解决Last-modified存在的一些问题: 某些服务器不能精确得到资源的最后修改时间,这样就无法通过最后修改时间判断资源是否更新 如果某些资源修改非常频繁,在秒一下的时间内进行修改,而last-modified 只能精确到秒。 一些资源的最后修改时间改变了,但是内容没改变,使用Etag 就认为资源还是没有修改的
根据查到的资料显示,缓存头的优先级是这样的: Pragma > Cache-Control > Expires > Etag > Last-Modified
缓存策略至于缓存策略的制定,我们可以参照Google官方的这张图 由于图上都是英文,我猜像我这样的菜鸟都看不懂,这里借资料来解释一下: 当我们的资源内容不可复用时,直接为 Cache-Control 设置no-store ,拒绝一切形式的缓存;否则考虑是否每次都需要向服务器进行缓存有效确认,如果需要,那么设 Cache-Control 的值为 no-cach e;否则考虑该资源是否可以被代理服务器缓存,根据其结果决定是设置为 private 还是public ;然后考虑该资源的过期时间,设置对应的 max-age 和s-maxage 值;最后,配置协商缓存需要用到的 Etag、Last-Modified 等参数。
根据上面的基础知识和解读,我们可以知晓:在制定缓存策略时,需要牢记以下技巧: 使用一致的网址:如果您在不同的网址上提供相同的内容,将会多次获取和存储这些内容。提示:网址区分大小写。 确保服务器提供验证令牌(Etag ):有了验证令牌,当服务器上的资源未发生变化时,就不需要传送相同的字节。 确定中间缓存可以缓存哪些资源:对所有用户的响应完全相同的资源非常适合由CDN以及其他中间缓存进行缓存。 为每个资源确定最佳缓存周期:不同的资源可能有不同的更新要求。为每个资源审核并确定合适的max-age 。 确定最合适您的网站的缓存层次结构:您可以通过为HTML文档组合使用包含内容指纹的资源网址和短时间或no-cache 周期,来控制客户端获取更新的速度。 最大限度减少搅动:某些资源的更新比其他资源频繁。如果资源的特定部分(例如JavaScript函数或CSS样式集)会经常更新,可以考虑将其代码作为单独的文件提供。这样一来,每次获取更新时,其余内容(例如变化不是很频繁的内容库代码)可以从缓存获取,从而最大限度减少下载的内容大小
文章的最后我们还要说一下内存缓存(from memory cache )和硬盘缓存(from disk cache )。 内存缓存内存缓存有两个特点,分别是快速读取和时效性。 硬盘缓存硬盘缓存- 则是将缓存直接写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。 那么哪些文件会被放入内存中呢? 事实上,这个划分规则,一直以来是没有定论的。不过想想也可以理解,内存时有限的,很多时候需要先考虑即时呈现的内存余量,再根据具体的情况决定分配给内存和磁盘的资源量的比重——资源存放的位置具有一定的随机性。 虽然划分规则没有定论,但根据日常开发中观察的结果,我们至少可以总结出这样的规律:资源存不存内存,浏览器秉承的是“节约原则”。我们发现,Base64格式的图片,几乎永远可以被塞进memory cache,这可以视作浏览器为节省渲染开销的“自保行为”;此外,体积不大的 JS、CSS 文件,也有较大地被写入内存的几率——相比之下,较大的 JS、CSS 文件就没有这个待遇了,内存资源是有限的,它们往往被直接甩进磁盘。 浏览器读取缓存的顺序为memory –> disk 好啦,着急忙慌整完了,正好零点,碎觉碎觉。
明天还要考试,关老爷保佑!!! 参考文章:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn http://www./2016/03/discussion-on-web-caching/#prettyPhoto
|