缓存是个奇葩,用好了提高效率,用不好可能带来麻烦。这里只讨论涉及到浏览器缓存的几个重要字段以及作用,不讨论其前世今生。
1. 浏览器缓存的几个重要字段:
Cache-Control: 参数说明
- max-age=5 表示5秒再次访问不会去服务器
- no-cache 不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
- no-store 不缓存
- public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
- 只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。
- Pragma: no-cache 与 Cache-Control是相同的作用。
最优的Cache-Control策略(盗图):
Date:
请求当前页面的时间,由服务器返回
Etag/if-None-Match:
服务端返回的资源Hash或指纹码。在第二次请求的时候会将这个值赋给if-None-Match,服务端会判断资源的Hash或指纹码和if-None-Match的值一致,如果不一致则返回最新的资源文件,如果一致则返回304.
Expires:
服务端返回的过期时间。如果在nginx里配置了expires,这个值就是在客户端第一次请求的时间加上expires的时间得到的日期,Cache-Control的秒数,也是这个expires换算的值, 如果指定这个值,服务端不会从Cache-Control里进行换算。客户端在第二次请求的时候,根据当前请求的时间减去Catche-Control的时间,算得的日期与expires的日期进行比较,如果比它大则说明已过期。
last-Modified/If-Modified-Since:
这种策略与Etag的策略是一致的,区别是一个是文件修改时间一个是资源的指纹。执行的过程也与Etag的基本y一致,在第一次请求时返回last-Modified时间,第二次请求时,将该值赋给If-Modified-Since, 服务器将该时间与文件修改时间进行比较,修改时间比If-Modified-Since的时间要晚,则返回最新的资源。
2. 各字段的处理的优先级(osc的编辑器不支持flow…………)
op0=>operation: Cache-Control/Experies
op1=>operation: Etag/if-None-Match
op2=>operation: last-Modified/If-Modified-Since
op0->op1->op2
PS: 这个地方需要知道一件事: 如果你设置了Cache-Control, 浏览器是优先读取缓存的,但是如果你用F5将跳过Cache-Control,需要到服务器去验证,这时命中缓存会返回304.如果你是用Enter键刷新页面,浏览器是会判断Cache-Control的,会从本地缓存中读取文件,这时你看network里是from cache.
3.静态文件的版本控制
通常情况下即使我们为开始了缓存机制可以减轻服务器的负担,但同时也带来了新的问题,如何才能及时的更新最新的静态文件?
###1. 文件内容的hash版本冗余机制
<script type="text/javascript" src="a_8244e91.js"></script>
优势:
- 线上的a.js不是同名文件覆盖,而是文件名+hash的冗余,所以可以先上线静态资源,再上线html页面,不存在间隙问题;
- 遇到问题回滚版本的时候,无需回滚a.js,只须回滚页面即可;
- 由于静态资源版本号是文件内容的hash,因此所有静态资源可以开启永久强缓存,只有更新了内容的文件才会缓存失效,缓存利用率大增;
- 修改静态资源后会在线上产生新的文件,一个文件对应一个版本,因此不会受到构造CDN缓存形式的攻击.
劣势:
- 如果一个很小的改动,可能都需要走一遍发布流程,需要一个自动化的处理过程。 可以通过发布工具来解决这个问题。
###2. 压缩传输 这方式需要后端服务的专门支持,将多个静态文件合并成一个进行传输,减少传输的次数。这需要后端的服务能够进行文件合并