缓存的概念
缓存的原理是浏览器向服务器首次请求获得数据后,保存了一份请求资源的响应副本。当用户再次发起相同的请求时,如果缓存命中,则拦截请求,直接从缓存中获取响应副本。
缓存有很多种:代理缓存、网关缓存、浏览器缓存、内容分发网络、负载均衡器等,他们大致可以分为两类:共享缓存和私有缓存。
缓存的优点:
- 避免数据的冗余请求,节省流量计费
- 减少服务器的负担,提升性能
- 加快浏览器的响应速度,提升用户体验感
浏览器缓存
浏览器缓存即http缓存,它可以细分为强制缓存和协商缓存,两者的区别是当浏览器缓存命中时,是否需要向服务器发起请求,询问是否可以使用缓存中的响应资源。具体如下图所示:
浏览器首次向服务器发送请求时,服务器返回的响应头中涉及到浏览器缓存的有Expires、Cache-Control、last-modify、Etag。 Expires是之前http版本中使用的,现在更多的使用的是cache-control.
cache-control中有以下个字段:
- max-age:用来设置资源(representations)可以被缓存多长时间,单位为秒;
- s-maxage:和max-age是一样的,不过它只针对代理服务器缓存而言;
- public:指示响应可被任何缓存区缓存;
- private:只能针对个人用户,而不能被代理服务器缓存;
- no-cache:强制客户端直接向服务器发送请求,也就是说每次请求都必须向服务器发送。服务器接收到 请求,然后判断资源是否变更,是则返回新内容,否则返回304,未变更。这个很容易让人产生误解,使人误以为是响应不被缓存。实际上Cache-Control: no-cache是会被缓存的,只不过每次在向客户端(浏览器)提供响应数据时,缓存都要向服务器评估缓存响应的有效性。(就是协商缓存的机制)
- no-store:禁止一切缓存(这个才是响应不被缓存的意思)。
last-modify、Etag 是使用在协商缓存中的。
强制缓存中的header的参数(响应头)
Expires:过期时间,如果设置了时间,在这个时间内缓存命中时,浏览器直接从缓存中获取响应数据,不向服务器发送请求。是以分钟为单位
cache-control:若设置max-age=300,则代表5分钟之内再次发起相同请求,则命中强制缓存。是以秒为单位。
协商缓存中的header的参数
设置cache-control: no-cache。
last-modified && if-modified-since: 服务器返回给浏览器last-modified参数代表的是当前资源的最后修改时间,而浏览器向服务器发送请求时带上if-modified-since参数,即last-modified时间,服务器在收到浏览器发送的这个时间后,会与该资源的修改时间做对比,如果相等,则说明服务器中的资源没有被修改过,因此会返回给浏览器304,让浏览器从缓存中读取。
etag && if-non-match: 上面的匹配是会有问题的,因为last-modified存储的时间单位是s,如果在1s内多次修改了资源,那返回的时间是不变的,那在对比时间的时候浏览器发送的时间和服务器中资源的修改时间还是相同的,服务器会以为没有修改但其实是修改了的,因此就有了这种匹配。etag存储的是与资源相对应的哈希值(唯一标识),如果修改了资源,服务器会重新生成哈希值,因此通过是否是同一个哈希值匹配就更加准确。但是也会加重服务器的负担,性能上略逊于last-modified。
浏览器缓存的流程
- 浏览器第一次发起请求,从服务器中获取到资源,将响应头和过期时间一并存入缓存中
- 浏览器发起相同请求后,会计算当前时间和上一次请求返回200时的时间差,如果该事件没有超过cache-control中的max-age(如果浏览器不支持HTTP1.1,则用expires判断是否过期),则命中强制缓存,如果时间过期了,浏览器会带上if-modified-since和if-non-match向服务器发送请求。
- 浏览器收到请求后会优先根据etag的值判断是否修改了资源,如果匹配,则命中缓存协商,则返回304响应,通知浏览器可以从缓存中获取资源,否则就返回新的资源带上新的etag值,返回200
- 如果浏览器发起的请求中没有if-non-match参数,那就根据if-modified-since参数匹配,如果两个都没有,则直接返回资源并返回200。