我们在请求一个静态文件的时候(图片,css,js),这些文件的特点是文件不经常变化,将这些不经常变化的文件存储起来,对客户端来说是一个优化用户浏览体验的方法。那么这个就是客户端缓存的意义了,而Http 缓存机制则是作为 web 性能优化的重要手段。HTTP缓存有多种规则,根据是否需要重新向服务器发起请求来分类,可以将其分为两大类(强制缓存,对比缓存)。
我们从上面的时序图可以看到两类缓存规则的不同,强制缓存如果生效,不需要再和服务器发生交互,而对比缓存不管是否生效,都需要与服务端发生交互。两类缓存规则可以同时存在,强制缓存优先级高于对比缓存。
强制缓存
强制缓存,在缓存数据未失效的情况下,可以直接使用缓存数据,那么浏览器是如何判断缓存数据是否失效呢?我们知道,在没有缓存数据的时候,浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中。对于强制缓存来说,响应header中会有两个字段来标明失效规则(Expires/Cache-Control)使用chrome的开发者工具,可以很明显的看到对于强制缓存生效时,网络请求的情况。
Expires
Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。 不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。另一个问题是,到期时间是由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。所以HTTP 1.1 的版本,使用Cache-Control替代。
Cache-Control
Cache-Control 是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。
1 | private: 客户端可以缓存 |
例如下图:
图中Cache-Control指定了max-age,缓存时间为60秒,也就是在60秒内再次请求这条数据,都会直接获取缓存数据库中的数据,直接使用。如果有的服务器同时设置了Expires和Cache-Control怎么办呢?由于Cache-Controll是HTTP1.1中才有的,所以就是根据更先进的设置Cache-Control来为标准。
对比缓存
浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。对于对比缓存来说,缓存标识的传递是我们着重需要理解的,它在请求header和响应header间进行传递,一共分为两种标识传递:
Last-Modified / If-Modified-Since
Last-Modified:服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since:再次请求服务器时,通过该字段通知服务器上次请求时,服务器返回的资源最后修改时间。服务器收到请求后发现有If-Modified-Since 则与被请求资源的最后修改时间进行比对。若资源的最后修改时间大于If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码200;若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
Etag / If-None-Match(优先级高于Last-Modified / If-Modified-Since)
第一次客户端访问资源的时候,服务端返回资源内容的同时返回了ETag:1234,告诉客户端:这个文件的标签是1234,我如果修改了我这边的资源的话,这个标签就会不一样了。第二次客户端访问资源的时候,由于缓存中已经有了Etag为1234的资源,客户端要去服务端查询的是这个资源有木有过期呢?所以带上了If-None-Match: 1234。告诉服务端:如果你那边的资源还是1234标签的资源,你就返回304告诉我,不需要返回资源内容了。如果不是的话,你再返回资源内容给我就行了。服务端就比较下Etag来看是返回304还是200。
各种刷新
刷新有三种:
1.浏览器中写地址,回车:浏览器发现缓存中有这个文件了,好了,就不发送任何请求了,直接去缓存中获取展现。(最快)
2.F5 ,就是让浏览器好歹去看看这个文件是否有过期了,发一个请求带上If-Modify-since,如果这个时间后还没修改过,不需要给你任何信息了,返回304就行了。
3.Ctrl+F5:强制刷新,就是把缓存种的文件给删了,再去服务器请求个完整的资源文件下来。