① 浏览器缓存(http缓存)
浏览器缓存有两种:强制缓存和协商缓存
向浏览器缓存中查找请求结果,根据【缓存规则】决定是否使用该结果。
强制缓存失效后,携带缓存标识请求服务器,服务器根据缓存标识判断是否使用缓存
当浏览器向服务器发送请求的时候,服务器会将缓存规则放入HTTP响应的报文的HTTP头中和请求结果一起返回给浏览器(ps:下文说的时间点均为类似:Sat Aug 14 2021 11:01:52,秒级)
两个字段:Expires和Cache-Control,优先级:Cache-Control > Expires,客户端比较时间
Expires :HTTP/1.0,返回值为【到期时间点】,再次请求,客户端的时间< Expires,直接用缓存(ps:客户端与服务器端时间可能存在误差,出问题)
Cache-Control :HTTP/1.1,有以下字段
Last-Modified / If-Modified-Since 和 Etag / If-None-Match,优先级Etag > Last-Modified,服务器比较时间
Last-Modified(服务端返回客户端) / If-Modified-Since(客户端传入服务端) :两个值相同,表示:资源文件在服务器最后被修改的时间【时间点】。
Etag(服务端返回客户端) / If-None-Match(客户端传入服务端) ,两个值相同,为当前资源文件的一个唯一标识(由服务器生成)
Etag什么时候用
雅虎禁用了Etag:因为ETag的值和服务器有关,那么对于同样的文件,可能下次请求的时候是发给不同的服务器,结果也会重新发送数据,所以就会影响网页加载速度,增加服务器的压力(但Last-Modified也与服务器有关)
主要解决的问题:
浏览器的每个tab都是一个进程
两个缓存的地方 from memory cache(内存缓存) 和 from disk cache(硬盘缓存) ,读取顺序为memory > disk
② 系列分享之浏览器、本地DNS缓存篇
我们在使用浏览器访问互联网资源时,想获取指定的服务和信息。首先就要了解浏览器是如何定位到我们的站点的。输入一个域名(如:www.jd.com)浏览器会首先从自身的缓存中查询是否有历史域名对应的IP并且有效,如果有就使用该缓存通过IP直接访问到指定的站点。如果没有则查询本地的Host缓存,如果有就使用本地的缓存直接访问站点,没有则向本地DNS服务器发起请求查询,如果本地DNS服务也没有找到,则向公网DNS服务发起查询请求获取对应的有效IP,并返回缓存到浏览器和本地缓存中,供后续请求使用。
DNS记录会有一个ttl值(time to live),单位是秒,意思是这个记录最大有效期是多少。操作系统缓存会参考ttl值,但是不完全等于ttl值,而浏览器DNS缓存的时间跟ttl值无关,每种浏览器都使用一个固定值。
DNS查询请求类型:
1、权威答复:权威答复是返回给客户的正向答复,并且设置了DNS消息中的权威位。此答复代表从具有权威的DNS服务器处发出。
2、正向答复:正向答复包含了匹配客户端解析请求的资源记录。
3、参考答复:参考答复只在DNS服务器工作在迭代模式下使用,包含了其他有助于客户端解析请求的信息。例如,当DNS服务器不能为客户端发起的解析请求找到某个匹配值时,则向DNS客户端发送参考回复,告诉它有助于解析请求的信息。
4、否定答复:否定答复指出权威服务器在解析客户端的请求时可能遇到了以下两种情况之一:
权威DNS服务器报告客户端查询的名字不存在;
权威DNS服务器报告存在对应的名字,但是不存在指定类型的资源记录。
DNS服务器解析返回IP分配策略与客户端对域名IP选择策略,无论正向答复还是否定答复,DNS客户端都将结果保存在自己的本地缓存中
浏览器缓存:
浏览器在获取网站域名的实际IP地址后会对其IP进行缓存,减少网络请求的损耗。每种浏览器都有一个固定的DNS缓存时间。
参考浏览器DNS缓存时间:
本地缓存:
每种操作系统都有自己的DNS缓存时间控制。
1、Windows DNS默认值是MaxCacheTTL,它的默认值是86400s,也就是一天。
2、MacOS遵循DNS协议中的TTL,根据各种网络协议不同对不同的域名采用不同的缓存时间策略。在IPv4包头中TTL是一个8 bit字段,它位于IPv4包的第9个字节。
参考本地DNS缓存时间:
在命令行执行nslookup指令可以看到一个域名对应的IP地址,并且可以帮助我们判断是否有DNS劫持。随便解析一个网站,比如
www.jd.com 应该返回的是正常的地址
然后再解析一个不存在的网站,比如123123.aaaa.com.cn如果返回的结果是
DNS request timed out.
timeout was 2 seconds.
那么证明你的DNS没有被劫持。
如果返回的结果是一个IP地址,比如说网通的返回地址是230.xxx.xxx.xxx,那么证明你的DNS被劫持了。
通过了解浏览器、本地缓存可以帮助我们更好的为用户服务。
1、大型的互联网公司都有IP流量监控,当发生网络故障或劫持时可以第一时间发现。
2、页面是我们与用户面对面沟通的渠道和方式,当我们的网页和服务呈现在用户面前时,我们要了解我们提供的服务是如何影响到用户的体验的,比如我们前端页面的JS、CSS等文件的动态版本号处理方式结合缓存是如何变化的,每次发版会对什么样的用户有影响,都需要严谨。
3、机房内部的各个应用程序服务,比如Zookeeper、Redis、RPC、DB在DNS缓存变化时,可能引起的网络抖动,是否会对用户请求造成影响,也是我们必须要注意的问题。
③ Okhttp解析(五)缓存的处理
大家好,之前我们讲解了Okhttp网络数据请求相关的内容,这一节我们讲讲数据缓存的处理。本节按以下内容讲解Okhttp缓存相关的内容。
缓存的使用场景很多,通过它可以将数据通过一定的规则存储起来,再次请求数据的时候就可以快速从缓存中读取了,缓存有以下优势。
HTTP本身提供了一套缓存相关的机制。这套机制定义了相关的字段和规则,用来客户端和服务端进行缓存相关的协商,如响应的数据是否需要缓存,缓存有效期,缓存是否有效,服务器端给出指示,而客户端则根据服务端的指示做具体的缓存更新和读取缓存工作。http缓存可以分为两类:
强制缓存,在缓存数据未失效的情况下,可以直接使用缓存数据,有两个字段Expires和Cache-Control用于标明失效规则。
表示过期时间,由服务端返回。那么下次请求数据时,判断这个Expires过期时间是否已经过了,如果还没有到过期时间,则使用缓存,如果过了过期时间,则重新请求服务器的数据。Expires格式如下:
不过因为服务器和客户端的时间并不是同步的,用一个绝对时间作为过期的标记并不是很明智,所以HTTP1.1之后更多的是Cache-Control,它的控制更加灵活。
表示缓存的控制,有服务端返回。它有以下几个取值:
默认情况下是private,也就是不能共享的。Cache-Control格式如下:
对比缓存,表示需要和服务端进行相关信息的对比,由服务器决定是使用缓存还是最新内容,如果服务器判定使用缓存,返回响应吗304,判定使用最新内容,则返回响应码200和最新数据。对比缓存的判定字段有两组:
ETag表示资源的一种标识信息,用于标识某个资源,由服务端返回,优先级更高。格式如下:
然后客户端再次请求时,加入字段If-None-Match,格式如下:
服务端收到请求的该字段时(之前的Etag值),和资源的唯一标识进行对比,如果相同,说明没有改动,则返回状态码304,如果不同,说明资源被改过了,则返回状态码200和整个内容数据。
Last-Modified表示资源的最近修改时间,由服务端返回,优先级更低。格式如下:
Last-Modified
由服务器返回,表示响应的数据最近修改的时间。
If-Modified-Since
由客户端请求,表示询问服务器这个时间是不是上次修改的时间。如果服务端该资源的修改时间小于等于If-Modified-Since指定的时间,说明资源没有改动,返回响应状态码304,可以使用缓存。如果服务端该资源的修改时间大于If-Modified-Since指定的时间,说明资源又有改动了,则返回响应状态码200和最新数据给客户端,客户端使用响应返回的最新数据。
Last-Modified字段的值(服务端返回的资源上次修改时间),常常被用于客户端下次请求时的If-Modified-Since字段中。
HTTP的缓存规则是优先考虑强制缓存,然后考虑对比缓存。
Okhttp缓存相关的类有如下:
要开启使用Okhttp的缓存其实很简单,只需要给OkHttpClient对象设置一个Cache对象即可,创建一个Cache时指定缓存保存的目录和缓存最大的大小即可。
那么下面我们来看看Okhttp缓存执行的大概流程
Okhttp的缓存流程分为读取缓存和存储缓存两个过程,我们分别分析。
读取使用缓存的流程从HttpEngine的sendRequest发送请求开始。
接下来我们分析
从Cache的get方法开始。它按以下步骤进行。
如果存在缓存的话,在指定的缓存目录中,会有两个文件“****.0”和“****.1”,分别存储某个请求缓存的响应头和响应体信息。(“****”是url的md5加密值)对应的ENTRY_METADATA响应头和ENTRY_BODY响应体。缓存的读取其实是由DiskLruCache来读取的,DiskLruCache是支持Lru(最近最少访问)规则的用于磁盘存储的类,对应LruCache内存存储。它在存储的内容超过指定值之后,就会根据最近最少访问的规则,把最近最少访问的数据移除,以达到总大小不超过限制的目的。
接下来我们分析CacheStrategy缓存策略是怎么判定的。
直接看CacheStrategy的get方法。缓存策略是由请求和缓存响应共同决定的。
接来下我们看看CacheControl类里有些什么。
可以发现,它就是用于描述响应的缓存控制信息。
然后我们再看看Okhttp存储缓存是怎么进行的。
存储缓存的流程从HttpEngine的readResponse发送请求开始的。
可以看到这里先通过maybeCache写入了响应头信息,再通过cacheWritingResponse写入了响应体信息。我们再进去看Cache的put方法实现。
我们继续看Cache的writeTo方法,可以看到是写入一些响应头信息。
到这里Okhttp缓存的读取和存储流程我们就清楚了。可以说,缓存的使用策略基本都是按照HTTP的缓存定义来实现的,所以对HTTP缓存相关字段的理解是很重要的。然后关于DiskLruCache是如何管理缓存文件的,这个其实也很好理解,首先的原则就是按照LRU这种最近最少使用删除的原则,当总的大小超过限定大小后,删除最近最少使用的缓存文件,它的LRU算法是使用LinkedHashMap进行维护的,这样来保证,保留的缓存文件都是更常使用的。具体实现大家可以分析DiskLruCache和LinkedHashMap的实现原理。
④ 认识HTTP----缓存篇
本文内容大多参考 《图解HTTP》一书
所以讲缓存为什么要先扯代理服务器?别急,让我们看一下一个请求的简单示意图。
我们看到客户端(用户)发送了一个请求并不是直接发给源服务器的而是经过了代理服务器,然后经由代理服务器再发送给源服务器,响应也同样遵循这个顺序。
那么代理服务器在这中间担任了什么角色?
缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。
缓存服务器的优势在于利用缓存可避免多次从源服务器转发资源。因此客户端可就近从缓存服务器上获取资源,而源服务器也不必多次处理相同的请求了。
即便缓存服务器和客户端内有缓存,也不能每次都给我返回缓存吧,如果是这样,源服务器更新了我也不知道,因为我每次都是看缓存的资源。
为了解决这个问题,针对缓存设计了时效性的概念:
即使存在缓存,也会因为客户端的要求、缓存的有效期等因素,向源服务器确认资源的有效性。若判断缓存失效,缓存服务器将会再次从源服务器上获取“新”资源。
缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。以Internet Explorer 程序为例,把客户端缓存称为临时网络文件(Temporary Internet File)。
浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取。
另外,和缓存服务器相同的一点是,当判定缓存过期后,会向源服务器确认资源的有效性。若判断浏览器缓存失效,浏览器会再次请求新资源。
Pragma 是HTTP/1.1 之前版本的历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义。
规范定义的形式唯一,如下所示。
Pragma: no-cache
该首部字段属于通用首部字段,但只用在客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源。
通过指定首部字段Cache-Control 的指令,就能操作缓存的工作机制。
可用的指令按请求和响应分类如下所示:
public指令
Cache-Control: public
当指定使用public 指令时,则明确表明其他用户也可利用缓存。
private指令
no-store指令
Cache-Control: no-store
当使用no-store 指令时,暗示请求(和对应的响应)或响应中包含机密信息。
因此,该指令规定缓存不能在本地存储请求或响应的任一部分。
ps:从字面意思上很容易把no-cache误解成为不缓存,但事实上no-cache代表不缓存过期的资源,缓存会向源服务器进行有效期确认后处理资源,也许称为do-not-serve-from-cache-without-revalidation更合适。no-store 才是真正地不进行缓存,请读者注意区别理解。
s-maxage指令
Cache-Control: s-maxage=604800 //(单位:秒)
s-maxage 指令的功能和max-age 指令的功能相同, 它们的不同点是s-maxage 指令只适用于供多位用户使用的公共缓存服务器(这里指代理服务器)。也就是说,对于向同一用户重复返回响应的服务器来说,这个指令没有任何作用。
另外,当使用s-maxage 指令后,则直接忽略对Expires 首部字段及max-age 指令的处理。
max-age指令
cache-extension token
Cache-Control: private, community="UCI"
通过 cache-extension 标记(token),可以扩展Cache-Control 首部字段内的指令。
如上例,Cache-Control 首部字段本身没有community 这个指令。借助extension tokens 实现了该指令的添加。如果缓存服务器不能理community 这个新指令,就会直接忽略。因此,extension tokens 仅对能理解它的缓存服务器来说是有意义的。
If-Unmodified-Since: Thu, 03 Jul 2012 00:00:00 GMT
首部字段If-Unmodified-Since 和首部字段If-Modified-Since 的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码412 Precondition Failed 作为响应返回。
ps:Last-Modified 存在一定问题,如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会因为Last-Modified时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。
首部字段If-None-Match 属于附带条件之一。它和首部字段If-Match 作用相反。用于指定If-None-Match 字段值的实体标记(ETag)值与请求资源的ETag 不一致时,它就告知服务器处理该请求。
在GET 或HEAD 方法中使用首部字段If-None-Match 可获取最新的资源。因此,这与使用首部字段If-Modified-Since 时有些类似。
不与服务器确认,而是直接使用浏览器缓存的内容。其中响应内容和之前的响应内容一模一样,例如其中的Date时间是上一次响应的时间。
F5的作用和直接在URI输入栏中输入然后回车是不一样的,F5会让浏览器无论如何都发一个HTTP Request给Server,即使先前的响应中有Expires头部。
Ctrl+F5要的是彻底的从Server拿一份新的资源过来,所以不光要发送HTTP request给Server,而且这个请求里面连If-Modified-Since/If-None-Match都没有,这样就逼着Server不能返回304,而是把整个资源原原本本地返回一份,这样,Ctrl+F5引发的传输时间变长了,自然网页Refresh的也慢一些。
Cache-Control 是 HTTP1.1 才有的,不适用于 HTTP1.0,而 Expires 既适用于 HTTP1.0,也适用于 HTTP1.1,所以说在大多数情况下同时发送这两个头会是一个更好的选择,当客户端两种头都能解析的时候,会优先使用 Cache-Control。
二者都是通过某个标识值来请求资源, 如果服务器端的资源没有变化,则自动返回 HTTP 304 (Not Changed)状态码,内容为空,这样就节省了传输数据量。当资源变化后则返回新资源。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
其中Last-Modified使用文件最后修改作为文件标识值,它无法处理文件一秒内多次修改的情况,而且只要文件修改了哪怕文件实质内容没有修改,也会重新返回资源内容;ETag作为“被请求变量的实体值”,其完全可以解决Last-Modified头部的问题,但是其计算过程需要耗费服务器资源。
Expires和Cache-Control都有一个问题就是服务端的修改,如果还在缓存时效里,那么客户端是不会去请求服务端资源的(非刷新),这就存在一个资源版本不符的问题,而强制刷新一定会发起HTTP请求并返回资源内容,无论该内容在这段时间内是否修改过;而Last-Modified和Etag每次请求资源都会发起请求,哪怕是很久都不会有修改的资源,都至少有一次请求响应的消耗。
对于所有可缓存资源,指定一个Expires或Cache-Control max-age以及一个Last-Modified或ETag至关重要。同时使用前者和后者可以很好的相互适应。
前者不需要每次都发起一次请求来校验资源时效性,后者保证当资源未出现修改的时候不需要重新发送该资源。而在用户的不同刷新页面行为中,二者的结合也能很好的利用HTTP缓存控制特性,无论是在地址栏输入URI然后输入回车进行访问,还是点击刷新按钮,浏览器都能充分利用缓存内容,避免进行不必要的请求与数据传输。
做法很简单,就是把可能会更新的资源以版本形式发布,常用的方法是在文件名或参数带上一串md5或时间标记符:
可以看到上面的例子中有不同的做法,有的在URI后面加上了md5参数,有的将md5值作为文件名的一部分,有的将资源放在特性版本的目录中。
那么在文件没有变动的时候,浏览器不用发起请求直接可以使用缓存文件;而在文件有变化的时候,由于文件版本号的变更,导致文件名变化,请求的url变了,自然文件就更新了。这样能确保客户端能及时从服务器收取到新修改的文件。通过这样的处理,增长了静态资源,特别是图片资源的缓存时间,避免该资源很快过期,客户端频繁向服务端发起资源请求,服务器再返回304响应的情况(有Last-Modified/Etag)。
⑤ 缓存Cache-Control
首先附上前面提到的一张图:
根据上面的这张图,来说http协议中的缓存,也就是cache-control将会格外清晰。
Cache-Control包括哪些特性呢?
第一,可缓存性:public private no-cache 。可缓存性指http的response进过的哪些地方可以进行缓存。public指在response返回经过的任何地方都可以缓存,包括代理服务器,客户端等,这样下次请求将不会到达服务端而直接返回response;private则表示只有返回的浏览器才可以进行缓存;no-cache则表示不可直接用缓存,而是先要到服务器端进行验证。
第二,到期:max-age=<seconds> ,代表缓存的时间(秒); s-maxage=<seconds> ,专门为代理服务器设置,如果与max-age同时返回,则浏览器会读取max-age,而代理服务器则会读取s-maxage这个设置; max-stale=<seconds> ,代表在max-age过期后,如果存在max-stale,而且其时间没有过期,则表示仍然可以用缓存,max-stale只在request发起端设置是有用的,又因为浏览器不会帮助我们带上这个头,所以客户端是浏览器的时候这个max-stale是用不到的。
第三,重新验证:must-revalidate和proxy-revalidate ,这两个表示缓存过期时间到达以后,必须要到服务端重新请求和重新验证,这两个属性在浏览器也不怎么出现。
第四,其他,no-store ,表示本地和代理服务器都不可以用缓存,必须去重新获取; no-transform ,告诉代理服务器不要对返回的body进行处理,比如压缩等(代理服务器比如nginx等可以不遵守,但是这个是规范,最好遵守)。
下面附上做的几个简单的例子来加深对上面的理解 。例子中通过查看对文件script.js的缓存情况说明问题。
执行node server.js,观察浏览器network如下图(这里注意,浏览器的Disable cache没有勾选,否则会默认忽略Cache-Control的设置):
立刻重新刷新浏览器,则network中出现下图:
此时我们可以看见这事size一栏是from memory cache,因为我们设置max-age为20s,在这个期间即使我改变script.js的内容,浏览器仍然会用memory里面的内容,而得不到更新。很显然实际开发中,如果出现这样的问题,是很可怕的。同时如果每次去后端请求response,又会使网页很慢, 实际中max-age往往要设置很大 ,表示在本地保存很久的时间,那么下次请求的Time为0。那么实际开发中,如何去解决这两者的矛盾呢?就是通过改变url的方法, 在请求的文件名后面加上根据内容生成的哈希值 (刷新浏览器缓存的方案),这样实际请求的 url将会改变,那么自然就会去重新请求,如果后端的文件没有更新,也就是url没有变,则自然会在缓存中读取,则不需要经过网络传输,则速度是很快的,用户体验是很好的。 network一栏中,这里Size的两个值,上面表示传输时候的大小,下面表示实际的大小(上面的可进行压缩Gzip传输,但是不晓得header可不可以压缩,貌似http2中支持头压缩),传输时的大小比实际的大,因为加上了头信息。Time的两个值,上面一行表示从请求开始到接受完最后一个byte为止的时间。下面一行是Latency,代表从请求接受完到读取该资源第一个byte之间的等待时间。
上图是查找缓存的过程。
如果Cache-Control中max-age的值设置很大,那么一直用本地的缓存肯定是不可取的。所以除了给文件名后面加上哈希码之外的方法,我们可以通过每次去后端询问是否文件有所改动?那么如何来实现这个过程呢?首先在Cache-Control中设置no-cache,同时遵从实际情况我们把max-age设置很大。更改servr.js如下:
打开network,多次刷新仍然如下:
说明此时已经不在缓存中读取了,即使我们的max-age设置很大,这是因为我们设置了no-cache。所以每次我们都不会直接使用缓存了。那么如何发挥no-cache的作用呢,还需要配合资源验证,资源验证在http中主要有两个头:Last-Modified和Etag。这个内容介绍在-资源验证Last-Modified和Etag中介绍。
⑥ centosdns缓存时间
centosdns缓存时间24小时。根据查询相关资料信息显示,centos对dns服务器缓存时间是86400秒,一小时等于3600秒,因此是24小时,com对dns服务器缓存时间是48小时。通过centos客户端可以查询缓存的进度。
⑦ http缓存过程
注:http 缓存只能缓存 get 方式请求的资源
缓存是指 代理服务器 或 客户端本地磁盘 内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说, 当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本 。
缓存服务器的优势在于利用缓存可避免多次从源服务器转发资源。因 此客户端可就近从缓存服务器上获取资源,而源服务器也不必多次处 理相同的请求了。
浏览器缓存分 强制缓存 和 协商缓存 ,分别使用的字段前者是Expires和Cach-control,后者是 Etag 和 Last-modified。
Expires (http/1.0):设的是资源的过期时间(绝对时间),浏览器判断这次请求的时候是不是超过这个日期,没超的话就直接读取缓存中的资源,不向服务器发请求。
Pragma :字段值为“no-cache”的时候,会通知客户端不要对该资源读缓存,即每次都得向服务器发一次请求才行。但是这种禁用缓存的形式作用不是那么太大:1. 仅有IE才能识别这段meta标签含义,其它主流浏览器仅能识别“Cache-Control: no-store”的meta标签。2. 在IE中识别到该meta标签含义,并不一定会在请求字段加上Pragma,但的确会让当前页面每次都发新请求,但是仅限页面,页面上的资源则不受影响。
如果Pragma和Expires一起出现的话,Pragma的优先级是高的。
Cach-Control (http/1.1):缓存控制 示例:
Cache-Control 有三种属性:缓冲能力、过期时间和二次验证。
缓冲能力:
过期时间:
二次验证:
Expires使用的是服务端时间,可能出现客户端和服务端时间不同步,导致本地缓存无用或无法过期。
Max-Age使用的是客户端本地时间的计算,不会出现这个问题,推荐Max-Age。
如果同时启用了Cache-Control和Pragma ,Expires,Cache-Control优先级高。
Last-Modified / If- Modified-Since (http/1.0):判断资源最后修改时间,只要这个日期改变了就不使用缓存。浏览器的头部是If- Modified-Since,服务端的是Last-Modified,如果两个匹配,代表服务器资源未改变,服务端不会返回资源实体,只返回头部,通知浏览器使用缓存。
缺点:可能有些文件会周期性地改变日期,但是内容其实没变,但是该字段只判断最后修改时间,
E-tag / If-None-Match (http/1.1):Etag 是服务器针对请求的资源文件生成的唯一标识,只要文件内容没变化,则Etag值不变,克服了 Last-Modified / If- Modified-Since 的缺点。浏览器的头部是If-None-Match,服务端的是E-tag,如果两个匹配,代表内容未改变,通知浏览器使用缓存。
Etag 缺点:不适用于分布式系统 ,因为每个服务器上的 Etag 值不同。
如果同时带有E-tag和Last-Modified,服务端优先检查E-tag。
⑧ 浏览器缓存机制
有dns的地方,就有缓存。浏览器、操作系统、Local DNS、根域名服务器,它们都会对DNS结果做一定程度的缓存。
DNS查询过程如下:
首先搜索浏览器自身的DNS缓存,如果存在,则域名解析到此完成。
如果浏览器自身的缓存里面没有找到对应的条目,那么会尝试读取操作系统的hosts文件看是否存在对应的映射关系,如果存在,则域名解析到此完成。
如果本地hosts文件不存在映射关系,则查找本地DNS服务器(ISP服务器,或者自己手动设置的DNS服务器),如果存在,域名到此解析完成。
如果本地DNS服务器还没找到的话,它就会向根服务器发出请求,进行递归查询。
浏览器本地缓存失效后,浏览器会向CDN边缘节点发起请求。类似浏览器缓存,CDN边缘节点也存在着一套缓存机制。CDN边缘节点缓存策略因服务商不同而不同,但一般都会遵循http标准协议,通过http响应头中的
Cache-control: max-age 的字段来设置CDN边缘节点数据缓存时间。
当浏览器向CDN节点请求数据时,CDN节点会判断缓存数据是否过期,若缓存数据并没有过期,则直接将缓存数据返回给客户端;否则,CDN节点就会向服务器发出回源请求,从服务器拉取最新数据,更新本地缓存,并将最新数据返回给客户端。 CDN服务商一般会提供基于文件后缀、目录多个维度来指定CDN缓存时间,为用户提供更精细化的缓存管理。
CDN 优势
CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低。
大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源服务器的负载。
http请求报文(request)
请求行
请求方法 空格 URL 空格 协议版本 回车符 换行符
请求头(通用信息头、请求头、实体头)
头部字段名 冒号 值 回车键 换行符
...
头部字段名 冒号 值 回车键 换行符
空行
回车符 换行符
实体主体(只有post请求有)
主体
http响应报文(response)
状态行
协议版本 空格 状态码 空格 状态码描述 回车符 换行符
响应头部
头部字段名 冒号 值 回车符 换行符
...
头部字段名 冒号 值 回车符 换行符
空行
回车符 换行符
响应正文
正文
浏览器初次向服务器发起请求后拿到请求结果,会根据响应报文中HTTP头的缓存标识,决定是否缓存返回的结果,是则将请求结果和缓存标识存入浏览器缓存中
浏览器每次发起请求,都会现在浏览器缓存中查找该请求的结果以及缓存标识
浏览器 浏览器缓存 服务器
——————第一次发起http请求——————>
<——没有该请求的缓存结果和缓存标识————
——————————————发起http请求——————————————>
<——————————返回该请求结果和缓存规则————————————
——将请求结果和缓存标识存入浏览器缓存——>
强制缓存就是向浏览器缓存查找结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程
强制缓存的情况分为三种:
1、不存在该缓存结果和缓存标识,强制缓存失效,直接向服务器发起请求
2、存在该缓存结果和缓存标识,但结果已经失效,强制缓存失效,使用协商缓存
3、存在该缓存结果和缓存标识,且该结果没有失效,强制缓存生效,直接返回该结果
控制强制缓存的字段:Expires,Cache-Control
Expires 是 HTTP/1.0 控制缓存的字段,值为服务器返回该请求的结果缓存时间
即再次发送请求是,客户端时间 小于 Expires的值,直接使用缓存结果
Cache-Control 是HTTP/1.1的规则,主要用于控制网页缓存,主要取值为:
public:所有的内容都缓存(客户端和代理服务器都可以缓存)
private:所有内容只有客户端可以缓存(默认值)
no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
no-store:即不使用强制缓存,也不使用协商缓存
max-age=xxx:缓存内容将在xxx秒后失效
Expires 是一个绝对值
Cache-Control 中 max-age 是相对值,解决了 Expires时期 服务端与客户端 可能出现时间差的问题
注:Expires和Cache-Control同时存在时,只有Cache-Control生效
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程
协商缓存的两种情况:
1、协商缓存生效,返回304,继续使用缓存
过程:
浏览器 浏览器缓存 服务器
————————发起http请求————————>
<——该请求的缓存结果失效,只返回缓存标识——
————————携带该资源的缓存标识,发起http请求————————>
<—————————————304,该资源无更新————————————
——————获取该请求的缓存结果——————>
<——————返回该请求的缓存结果——————
2、协商缓存失败,返回200和请求结果
过程:
浏览器 浏览器缓存 服务器
————————发起http请求————————>
<——该请求的缓存结果失效,只返回缓存标识——
————————携带该资源的缓存标识,发起http请求————————>
<————————200,资源已更新,重新返回请求和结果———————
——将该请求结果和缓存标识存入浏览器缓存中—>
协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的
控制协商缓存的字段:
(1) Last-Modified/If-Modified-Since:Last-Modified是服务器响应请求是,返回该资源文件在服务器最后被修改的时间;If-Modified-Since再次发起请求时,携带上次返回的Last-Modified的值,服务器将该字段值与该资源最后修改时间对比,决定是否用缓存
(2)Etag/If-None-Match:Etag服务器响应请求时,返回当前资源文件的一个唯一标识,由服务器生成之;If-None-Match是再次发起请求时,携带上次返回的唯一标识Etag的值,服务器收到后,将该字段值与该资源在服务器上的Etag对比,一致 则返回304,否则返回200
注:Etag/If-None-Match优先级高于Last-Modified/If-Modified-Since,同时存在时只有Etag/If-None-Match生效
浏览器缓存分为:内存缓存 和 硬盘缓存
内存缓存特性:
(1)快速读取:内存缓存会将编译解析后的文件,存入该进程的内存中,便于下次运行时快速读取
(2)时效性:一旦关闭进程,进程内存清空
硬盘缓存特性:
永久性:直接写入硬盘文件中
复杂、缓慢:读取缓存对该缓存存放的硬盘文件进行I/O操作,重新解析
from memory cache:使用内存中的缓存
from disk cache:使用硬盘中的缓存
浏览器读取顺序:memory ——> disk
浏览器将js和图片等文件解析执行后直接存入内存缓存中,F5刷新页面时,from memory cache(使用内存中的缓存)
css文件存入硬盘中,F5刷新页面时,from disk cache(使用硬盘中的缓存)
参考文章
https://segmentfault.com/a/1190000017962411
https://www.cnblogs.com/chengxs/p/10396066.html
⑨ 浏览器中的缓存
在我们使用浏览器访问网页的过程中,浏览器经常会缓存各种网页中的内容。当再次访问同一个网页时,可以发现部分内容是从缓存直接读取的。
查看HTTP的响应信息,就能发现一些端倪。比如响应 200 from cache; 304 not modify 等等。
下面对浏览器使用缓存的各种情形做一下分析:
Pragma是HTTP 1.0版本的一个参数,在HTTP 1.1版本里面这个参数也会生效,如果不想浏览器缓存网页的内容,可以在 Response header 里面加上 :Pragma: no-cache。
Cache-Control是HTTP 1.1版本新增的一个参数。
Cache-Control:no-store 不允许缓存
Cache-Control:no-cache 不允许直接使用缓存,需要先发起请求和服务器协商(这个经常被误认为是不允许缓存,实际上它的作用是让浏览器在使用缓存前先请求服务端一次,确认内容是否有更新)
这样的响应代表没有跟服务端进行交互,内容是直接从本地读取的。
Expires和Cache-control: max-age= 有类似的作用,都是指定缓存内容的有效周期,Expires指定的格式是格林威治时间,max-age则是秒数。
服务端也可以在 Response header 里加上 Last-Modified,它的格式是格林威治时间,再次请求时,浏览器的 Request header 中会多出一个叫 If-Modified-Since的值,通过比较这两个值是否一致来决定是否返回304。
ETag的用法和 Last-Modified 类似,值是一种文件指纹。比如:ETag:"5a3ccff0-5dc"。
服务端在 Response header 里加上 ETag,再次请求时,浏览器的 Request header 中会多出一个叫 If-None-Match的值,通过比较这两个值是否一致来决定是否返回304。
总体来说,浏览器使用缓存时有两种表现:
1.直接从本地读取,不与服务端有交互,就是 200 OK (from memory cache)。
2.请求一次服务端,查看本地缓存是否生效,这种方式叫 协商缓存。如果服务端判断缓存有效,将不返回完整内容,而是返回 304 Not Modified。
在优先级上 Pragma > Cache-Control > Expires。