使用缓存的原因
HTTP协议是“无状态”的交互原则,意味着每次的请求都是独立的,如果在不缓存的情况下,不可避免的出现携带重复数据,导致网络性能降低。从HTTP1.0,到1.1到2.0,缓存形成了“状态缓存”,“强缓存”,“协商缓存”这三种机制。
三种缓存
状态缓存(了解)
HTTP缓存中,状态缓存是指客户端直接根据缓存信息对目标网站的状态进行判断的缓存,之前只有301/Moved Permanently(永久重定向)这一种,后来在RFC6797中增加了HSTS(HTTP Strict Transport Security),用于避免重定向跳转HTTPS时可能产生的劫持传输。
强缓存
强缓存在缓存未失效的情况下强制使用。在浏览器的地址输入、页面链接跳转、新建窗口、前进和后退中均生效,主动刷新页面除外。
实现方式
- Expires:Expires是HTTP1.0的产物,后面跟着截止时间,表示在时间结束前资源不会失效。
- 缺点:
- 截止时间是具体的时间:“Wed, Dec 07 2022 08:04:12 GMT”,如果客户端时间发生改变会导致失效异常。
- 只能缓存通用的资源,无法缓存认证的私有资源。如果缓存私有资源可能会导致资源被非认证用户获取。
- 没有“不缓存”的语义,只能通过每次设置的时间戳为当前时间来强制失效:.png?t=1586359920,虽然有Pragma:no-cache 表达不缓存,但在1.0中属于空实现,没有实际意义。
- 缺点:
- Cache-Control:HTTP1.0版本出现的,比Expires更加灵活,并且优先级更高。下面介绍下注意参数
- max-age:Cache-Control: max-age=800 表示在多少秒后失效,这里使用的是秒为单位的数值,解决了Expires因为本地时间导致的问题。
- s-maxage: 允许被CDN、代理等持有的有效时间,提醒服务器何时失效,其中s是share的缩写。
- public和private:涉及到私有资源权限问题,如果是public,可以被CDN、代理等缓存;如果是private只能有用户客户端私有缓存。
- no-cache: 《图解HTTP》解释为“不缓存过期的资源”,作用是强制缓存失效,但协商缓存依然有效。
- no-store:禁止浏览器、CDN以任何形式保存,但不强制会话中同一资源的重复获取(no-store不会导致强制重复获取的)
- no-transform:禁止任何修改。要求Content-Encoding、Content-Range、Content-Type都不能被修改。比方说某些代理会自动压缩图片或文本以提高性能。
- min-fresh:用户客户端请求,让服务端返回的max-age不能比该值小。
- only-if-cache:告诉服务端不用返回实体,客户端如果有缓存就使用缓存,没有就报503
- must-revalidate和proxy-revalidate:must-revalidate表示过期了就要重新请求,和no-cache一样;proxy-revalidate标签CDN,代理等设备资源过期后也要重新获取。
协商缓存
强缓存设置一个时间来确定过期,但过久发生变化是无法有确切时间的。协商缓存区别于强缓存多了一次变化检测,通过降低性能换取更高的一致性。主要的检测方式有两种:修改时间和唯一标识
通过修改时间判断
- Last-Modified:服务端返回的最终修改时间,单位到秒。Last-Modified:Wed, Dec 07 2022 08:04:12 GMT
- If-Modified-Since:客户端根据服务端获取的时间写入并发送给服务端校验。
- 如果没有被修改返回304,如果修改了提供新的修改时间和内容
通过唯一标识判断
- ETag:服务端返回的唯一标识,不同的服务端会用不同方式生成,例如Apache是将文件的索引节点,大小和修改时间通过hash后得到。
- If-None-Match:客户端根据ETag的表示写入并发送给服务端校验。
- 如果没修改返回304,修改了就返回新的标识和内容
Tips
协商缓存不仅在浏览器的地址输入、页面跳转、新建窗口、前进和后退、刷新页面都生效。只有在强制刷新(Ctrl+F5)时失效,因为Ctrl+F5不只是加了no-cache,还去掉了If-Modified-Since/If-None-Match导致协商缓存失效。