在整个大的应用体系中,缓存是节省流量,快捷高效的一环。
缓存的分类
- 源服务端缓存:比如 Nginx、Apache
- 网络中缓存: 代理服务器缓存(共享缓存), 反向代理服务器缓存(网关缓存负载均衡, CDN)
- 浏览器缓存:HTTP 缓存、indexDB、cookie、localstorage 等等
优点&缺点
-
使用缓存的优点:
- 请求更快
- 节省带宽
- 降低服务器压力
-
缺点
- 网站管理员特别希望知道网站的一举一动,比方说多少人访问,访问时间,而缓存会“隐藏”他们的用户,他们就无从得知到底谁访问了这个站点
(解决方法之一:可以选择页面上的一个小元素(或页面本身),然后给这个元素一个适当的头信息使它是不可缓存。比如,你可以在每一个页面上引用一个1像素×1像素的不可缓存(如scr地址后面加个随机数Add)的透明图片。Referer头信息将会包含调用它的页面信息。即使这样也不能给出你用户的精确统计,并且对通过互联网访问的用户也不是很友好:产生不必要的流量,并强迫用户等待未被缓存的内容从网络上下载回来) - 无法及时更新
- 网站管理员特别希望知道网站的一举一动,比方说多少人访问,访问时间,而缓存会“隐藏”他们的用户,他们就无从得知到底谁访问了这个站点
http缓存机制
规则 | 消息包头 | 值/示例 | 类型 | 作用 | 缺点/局限/注意 |
---|---|---|---|---|---|
新鲜度 | Expires | Mon, 15 Aug 2016 03:56:47 GMT | response | 启用缓存和定义缓存时间。告诉浏览器资源缓存过期时间,如果还没过该时间点则不发请求 | (http1.0)该时间是相对服务器的,因此存在客户端和服务端时间上不一致的问题。 |
Cache-Control | public | response | 任何路径的缓存者(本地缓存、代理服务器)均可缓存 | ||
private | response | 指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。 | |||
no-cache | response | 告诉浏览器忽略资源的缓存副本,强制每次请求直接发送给服务器,拉取资源,但不是“不缓存” | |||
no-store | response | 强制缓存在任何情况下都不要保留任何副本 | |||
max-age | response | 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。上次缓存时间(客户端的)+max-age(64200s)<客户端当前时间 | |||
min-fresh | response | 指示客户机可以接收响应时间小于当前时间加上指定时间的响应 | |||
max-stale | response | 指示客户机可以接收超出超时期间的响应消息 | |||
Pragma | no-cache | response | http1.0中存在的字段,在http1.1已被抛弃,使用Cache-Control替代,但为了做http协议的向下兼容,很多网站依旧会带上这个字段 | ||
校验值 | Last-Modified | Mon, 15 Aug 2016 03:56:47 GMT | response | 标示这个响应资源的最后修改时间 | 只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间 。 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存,有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形(无法使用缓存)可以使用ETag |
If-Modified-Since | Mon, 15 Aug 2016 03:56:47 GMT | request | 当资源过期时(使用Cache-Control标识的max-age),其值为上次响应头的Last-Modified值,再次向web服务器请求时带上头If-Modified-Since。web服务器收到请求后发现有头If-Modified-Since则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),包括更新Last-Modified的值,HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304(无需包体,节省浏览),告知浏览器继续使用所保存的cache | 要配合Cache-Control使用 | |
Etag | “fd56273325a2114818df4f29a628226d” | response | 告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)如果有 Etag 字段,那么浏览器就会将本次缓存写入硬盘中,之后的缓存是from disk cache |
||
If-None-Match | “fd56273325a2114818df4f29a628226d” | request | 当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match(Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。 | Etag/If-None-Match也要配合Cache-Control使用。需要注意的是分布式系统里多台机器间文件的last-modified必须保持一致,以免负载均衡到不同机器导致比对失败,Yahoo建议分布式系统尽量关闭掉Etag(每台机器生成的etag都会不一样,因为除了 last-modified、inode 也很难保持一致)。 |
浏览器缓存机制
-
分类:
- 强缓存: 浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器。比如某个css文件,如果浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器。
- 协商缓存: 当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回(304),但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;若未命中请求,则将资源返回客户端,并更新本地缓存数据(200)。
- 强缓存与协商缓存区别:强缓存不发请求到服务器,协商缓存会发请求到服务器。
-
设置缓存
1 | <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> |
但是 仅有IE才能识别这段meta标签含义,其它主流浏览器仅识别“Cache-Control: no-store”的meta标签。
-
浏览器缓存位置
- Service Worker: 运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker的话,传输协议必须为 HTTPS
- Memory Cache (读取内存中的数据)
- Disk Cache
- Push Cache: 是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。并且缓存时间也很短暂,只在会话(Session)中存在,一旦会话结束就被释放
- 网络请求
-
机制
- 第一次请求:
- 再次发送请求时:
相关问题
- 我的图片缓存一个月后才到期,我现在就想变动怎么办?
最有效的方法是修改链接,这样会从源服务器获取完整的新内容。请记住,调用图片的这个页面也会被缓存的,正因如此,我们需要让图片以及其他类似的静态资源易缓存,而页面呢可以随着自身的改变(例如改变了一个图片的URL地址Add)即时更新。
大公司的静态资源优化方案,基本上要实现这么几个东西:
- 配置超长时间的本地缓存 —— 节省带宽,提高性能
- 采用内容摘要作为缓存更新依据 —— 精确的缓存控制(对于修改的静态文件,资源,改变它的url或者说文件名)
- 静态资源CDN部署 —— 优化网络请求
- 更新资源发布路径实现非覆盖式发布 —— 平滑升级(先部署页面,再部署资源还是先部署资源,再部署页面问题)
我们可以将所有前端静态资源开启永久强缓存,每次版本发布都可以首先让静态资源全量上线,再进一步上线模板或者页面文件,再也不用担心各种缓存和时间间隙的问题了!
-
我的页面是密码保护的,代理缓存是怎么处理的?
-
如果人们通过缓存访问我的网站,我应该担心安全吗?
(答: SSL页面不会被代理服务器缓存,所以这个你不需要担心。但是,代理服务器就好非SSL页面请求以及URL抓取这口,你懂的,这是不安全的。无良的管理员可能就会收集网站用户的信息,尤其在URL中)
参考: