浏览器缓存主要分为强缓存(本地缓存)和协商缓存(弱缓存)
浏览器缓存(Brower Caching)是浏览器对之前请求过的文件进行缓存,以便下一次访问时重复使用,节省带宽,提高访问速度,降低服务器压力
http缓存机制主要在http响应头中设定,响应头中相关字段为Expires、Cache-Control、Last-Modified、Etag。
HTTP 1.0协议中的。简而言之,就是告诉浏览器在约定的这个时间前,可以直接从缓存中获取资源(representations),而无需跑到服务器去获取。
Expires因为是对时间设定的,且时间是Greenwich Mean Time (GMT),而不是本地时间,所以对时间要求较高。
如上图,在浏览器第一次发送请求后,需要再次发送请求时,浏览器会首先获取该资源缓存的header信息,然后根据Cache-Control和expires来判断是否过期。若没过期则直接从缓存中获取资源信息,包括缓存的header的信息,所以此次请求不会与服务器进行通信。如果缓存过期,浏览器会向服务器发送请求,本次请求会带着第一次请求返回的有关缓存的header字段信息,比如以下两种情况:
客户端会通过If-None-Match
头将先前服务器端返回的Etag发送给服务器,服务器会对比这个客户端发过来的Etag是否与服务器的相同,若相同,就将If-None-Match的值设为false,返回状态304,客户端继续使用本地缓存,不解析服务器端发回来的数据。若不相同就将If-None-Match的值设为true,返回状态为200,客户端重新机械服务器端返回的数据;
客户端还会通过If-Modified-Since
头将先前服务器端发过来的最后修改时间戳发送给服务器,服务器端通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回最新的内容,如果是最新的,则返回304,客户端继续使用本地缓存。
浏览器不会像服务器发送任何请求,直接从本地缓存中读取文件并返回Status Code: 200 OK
不访问服务器,一般已经加载过该资源且缓存在了内存当中,直接从内存中读取缓存。浏览器关闭后,数据将不存在(资源被释放掉了),再次打开相同的页面时,不会出现from memory cache。
不访问服务器,已经在之前的某个时间加载过该资源,直接从硬盘中读取缓存,关闭浏览器后,数据依然存在,此资源不会随着该页面的关闭而释放掉下次打开仍然会是from disk cache。
优先访问memory cache,其次是disk cache,最后是请求网络资源
强缓存是利用http头中的Expires
和Cache-Control
两个字段来控制的,用来表示资源的缓存时间
是http1.0的规范,它的值是一个绝对时间的GMT格式的时间字符串。比如网页的Expires值是:
expires:Mar, 06 Apr 2020 10:47:02 GMT
这个时间代表这这个资源的失效时间,只要发送请求时间是在Expires
之前,那么本地缓存始终有效,则在缓存中读取数据。所以这种方式有一个明显的缺点,由于失效的时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。
是http1.1中出现的,一般利用该字段的max-age
来判断,这个值是一个相对时间。例如:
Cache-Control:max-age=3600 // 代表着资源的有效期是3600秒
除了该字段还有其他的几个常用的值。
Cache-Control
与Expires
可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。比如:
cache-control:max-age=691200 expires:Fri, 06 Mar 2020 10:47:02 GMT
那么表示资源可以被缓存的最长时间为691200秒,会优先考虑max-age。
向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;
协商缓存是由服务器确定缓存资源是否可用。主要涉及到两组header字段:
Last-Modifed/If-Modified-Since和Etag/If-None-Match是分别成对出现的,呈一一对应关系
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间,例如
Last-Modify: Thu,31 Dec 2037 23:59:59 GMT
。
当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。如果命中缓存,则返回304,并且不会返回资源内容,并且不会返回Last-Modify。
从上面看可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?
首先,Etag/If-None-Match 是“实体标签”(Entity Tag)的缩写,是资源的一个唯一标识,资源变化都会导致ETag变化。服务器根据浏览器上送的If-None-Match值来判断是否命中缓存。
因此,Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
强制缓存是根据过期时间来使用的,协商缓存是根据文件有没有修改来使用的,如果过期了就需要使用协商缓存来确定文件有没有修改,如果修改了就需要服务器返回修改后的资源,如果没有修改就还是可以使用缓存的资源。
强缓存有缺点:比如说,设置了expires,GMT格式,但是浏览器的时间可以改变,因此就通过cache-control返回一个相对时间来。但是假如说资源并没有更新,但是强缓存时间过期了,那就需要重新拉去资源,因此就有了last-modified,但是last-modified的时间单位是s,当1s内有资源修改,那浏览器返回的最后修改时间和上次的修改时间相同,那就不会重新拉取资源,因此推出了etag,通过比对资源内容来判断是否修改