浏览器缓存类型
- 强缓存:不会向服务器发送请求,直接从缓存读取资源。在chrome控制台的network选项中可以看到该请求返回200状态码,并且size显示from disk cache或from memory cache。
- 协商缓存:向服务器发送请求,服务器会根据这个请求的request header的一些参数判断是否命中协商缓存。如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源。
两者的共同点是,都是从客户端缓存读取资源;区别是,强缓存不会发送请求,协商缓存会发送请求。
缓存有关的header
强缓存
- Expires:response header里的过期时间。浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。
- Cache-Control:当值设为max-age=300时,则代表这个请求正确返回时间(浏览器也会记录下来)的五分钟内再次加载资源,就会命中强缓存。
Expires和Cache-Control的作用差不多,区别是,Expires是http1.0的产物,Cache-Control是http1.1的产物。两者同时存在时,Cache-Control的优先级高于Expires,而在某些不支持http1.1的环境下,Expires就会发挥作用。因此,Expires是过时的,它只是一种兼容性的写法。
Expires和Cache-Control的另一个区别是,Expires是一个具体的服务器时间,这就导致,如果服务器和客户端的时间相差过大,缓存命中与否就不是开发者所期望的。而Cache-Control是一个时间段,就更加容易控制。
协商缓存
ETag和If-None-Match
ETag是上一次加载资源时,服务器返回的response header,是对该资源的一种唯一标识,只要资源有变化,ETag就会重新生成。浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的ETag值放到request header的If-None-Match里,服务器接收到If-None-Match的值后,会与该资源文件的ETag值作比较。如果相同,则表示资源文件没有发生改变,命中协商缓存。
Last-Modified和If-Modified-Since
Last-Modified是该资源文件最后一次更改时间,服务器会在response header中返回,同时浏览器会将这个值保存起来。在下一次加载资源向服务器发送请求时,放到request header里的If-Modified-Since中,服务器在接收后也会做对比,如果相同则命中协商缓存。
两种协商缓存的区别
- 精确度。ETag优于Last-Modified。Last-Modified的单位是秒,如果某个文件在一秒钟变更了多次,则它的Last-Modified无法体现出修改,而ETag则可以确保精度。如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。
- 性能。Last-Modified优于ETag,因为Last-Modified只需要记录时间,而ETag则需要服务器通过算法生成一个hash值。
- 优先级。ETag优先。
浏览器缓存过程
- 浏览器第一次加载资源时,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并将response header及该请求的返回时间一并缓存。
- 下一次加载资源时,先比较当前时间和上次返回200的时间差,如果没有超过Cache-Control设置的max-age,则命中强缓存,不发请求,直接从本地缓存读取该文件(如果浏览器不支持http1.1,则利用Expires判断是否过期);如果时间过期,则向服务器发送header带有If-None-Match和If-Modified-Since的请求。
- 服务器收到请求后,优先根据ETag判断被请求的资源有没有被修改。如ETag值没有被修改,则命中协商缓存,返回304;如果不一致则有改动,直接返回新的资源文件带上新的ETag值和状态码200。
- 如果服务器收到的请求没有If-None-Match(即ETag)值,则将If-Modified-Since和被请求文件最后的修改时间作对比,一直则命中协商缓存,返回304;否则直接返回新的资源文件带上新的Last-Modified和状态码200。
用户行为对浏览器缓存的控制
- 地址栏访问,链接跳转是正常用户行为,将会触发浏览器缓存机制;
- F5刷新,浏览器会设置max-age为0,跳过强缓存判断,进行协商缓存判断;
- Ctrl+F5刷新,跳过强缓存和协商缓存,直接从服务器拉取资源。
原文
- chenjiangsong,浏览器的缓存机制小结