赞
踩
对于客户端来说,HTTP缓存是web性能优化的重要手段。
优势:
缺点:
浏览器缓存一般是针对静态资源(js/css/img等),我们将缓存分为强缓存和协商缓存,两者的主要区别是使用本地缓存的时候,是否需要向服务器验证本地缓存是否依旧有效。顾名思义,协商缓存,就是需要和服务器进行协商,最终确定是否使用本地缓存。
Expires:响应头,代表该资源的过期时间。
Cache-Control:请求/响应头,缓存控制字段,精确控制缓存策略。
If-Modified-Since:请求头,资源最近修改时间,由浏览器告诉服务器。
Last-Modified:响应头,资源最近修改时间,由服务器告诉浏览器,和If-Modified-Since成对出现,。
Etag:响应头,资源标识,由服务器告诉浏览器。
If-None-Match:请求头,缓存资源标识,由浏览器告诉服务器,和Etag成对出现。
强制缓存整体流程比较简单,就是在第一次访问服务器取到数据之后,在过期时间之内不会再去重复请求。实现这个流程的核心就是如何知道当前时间是否超过了过期时间。
强制缓存的过期时间通过第一次访问服务器时返回的响应头获取。在 http 1.0
和 http 1.1
版本中通过不同的响应头字段实现。
http 1.0强缓存
在http1.0中,强缓存是通过expires响应头实现的,表示资源未来会过期的时间。该值是一个GMT时间格式个字符串,发起请求时间过了 expires设定的时间,表示资源缓存到期,会发送请求给服务器重新请求资源。如果发起请求时间没超过那么浏览器会直接读取本地缓存数据库中的信息(from memory cache or from disk cache)两种方式根据浏览器的策略随机获取。
from memory cache:字面理解是从内存中,其实也是字面的含义,这个资源是直接从内存中拿到的,不会请求服务器一般已经加载过该资源且缓存在了内存当中,当关闭该页面时,此资源就被内存释放掉了,再次重新打开相同页面时不会出现from memory cache的情况
from disk cache:同上类似,此资源是从磁盘当中取出的,也是在已经在之前的某个时间加载过该资源,不会请求服务器但是此资源不会随着该页面的关闭而释放掉,因为是存在硬盘当中的,下次打开仍会from disk cache
http 1.1强缓存
在 http 1.1
版本中,强制缓存通过 Cache-Control
响应头来实现。Cache-Control
拥有多个值
private:客户端可以缓存,不允许被中间代理服务器缓存。
public:客户端和代理服务器均可缓存;
max-age=xxx:缓存的资源将在 xxx 秒后过期;
no-cache:浏览器不做缓存检查;每次访问资源,浏览器都要向服务器询问,如果文件没变化,服务器只告诉浏览器继续使用缓存(304),需要使用协商缓存来验证是否过期;
no-store:浏览器和中间代理服务器都不能缓存资源
最常用的字段就是 max-age=xxx
,表示缓存的资源将在 xxx 秒后过期。一般来说,为了兼容,两个版本的强制缓存都会被实现。http 1.1
版本的实现优先级会高于 http 1.0
版本的实现。浏览器先检查 Cache-Control,如果有,则以 Cache-Control 为准,忽略 Expires。如果没有 Cache-Control,则以 Expires 为准。
协商缓存每次读取数据时都需要跟服务器通信,并且会增加缓存标识。在第一次请求服务器时,服务器会返回资源,并且返回一个资源的缓存标识,一起存到浏览器的缓存数据库。当第二次请求资源时,浏览器会首先将缓存标识发送给服务器,服务器拿到标识后判断标识是否匹配,如果不匹配,表示资源有更新,服务器会将新数据和新的缓存标识一起返回到浏览器;如果缓存标识匹配,表示资源没有更新,并且返回 304
状态码,浏览器就读取本地缓存服务器中的数据。
在 http 1.0
和 http 1.1
版本中也是不同的实现
http 1.0协商缓存
在 http 1.0
版本中,第一次请求资源时服务器通过 Last-Modified
来设置响应头的缓存标识,并且把资源最后修改的时间作为值填入,然后将资源返回给浏览器。在第二次请求时,浏览器会首先带上 If-Modified-Since
请求头去访问服务器,服务器会将 If-Modified-Since
中携带的时间与资源修改的时间匹配,如果时间不一致,服务器会返回新的资源,并且将 Last-Modified
值更新,作为响应头返回给浏览器。如果时间一致,表示资源没有更新,服务器返回 304 状态码,浏览器拿到响应状态码后从本地缓存数据库中读取缓存资源。
这种方式有一个弊端,就是当服务器中的资源增加了一个字符,后来又把这个字符删掉,本身资源文件并没有发生变化,但修改时间发生了变化。当下次请求过来时,服务器也会把这个本来没有变化的资源重新返回给浏览器。
http 1.1协商缓存
在 http 1.1
版本中,服务器通过 Etag
来设置响应头缓存标识。Etag
的值由服务端生成。在第一次请求时,服务器会将资源和 Etag
一并返回给浏览器,浏览器将两者缓存到本地缓存数据库。在第二次请求时,浏览器会将 Etag
信息放到 If-None-Match
请求头去访问服务器,服务器收到请求后,会将服务器中的文件标识与浏览器发来的标识进行对比,如果不相同,服务器返回更新的资源和新的 Etag
,如果相同,服务器返回 304
状态码,浏览器读取缓存。
同样的,一般来讲为了兼容,两个版本的协商缓存都会被实现,http 1.1
版本的实现优先级会高于 http 1.0
版本的实现。
etag主要解决了Last-Modified一些无法解决的问题
一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新get;
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),if-modified-since能检查到的粒度是秒级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
某些服务器不能精确的得到文件的最后修改时间。
- res.setHeader('Cache-Control', 'public, max-age=258900');
- res.setHeader('Last-Modified', Mon, 24 Dec 2019 09:49:49 GMT);
- res.setHeader('ETag', '5c20abbd-e2e8');
了解了强缓存和协商缓存,会发现无论单独使用哪一种都无法满足我们的需要,建议:
1.HTML采用协商缓存,用户每次请求index.html不拿浏览器缓存,直接请求服务器,这样就保证资源更新了,用户能马上访问到新资源,如果服务端返回304,这时候再拿浏览器的缓存的index.html。
2.JS/CSS/IMG采用强缓存,打包的时候给文件名加上hash值
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。