【法医奇遇记】蛋糕店与HTTP缓存协议

爱情这个词绝对不是虚幻的、精神的,而是客观的、物质的,是一系列化学反应的结果,每一次爱情的发生都分为三个阶段,而每一个阶段都受制于特定激素的影响而发生。

第一个阶段的重要激素叫苯基乙胺,是一种大脑分泌的神经兴奋剂,当你对一个人产生意乱神迷的感觉时,爱情的萌芽就发生了,而第一种激素最需要的就是时机,一个特别适合的场合,或者一场浪漫的邂后都是最有效的。

奇遇场合:蛋糕店

今天的主人公叫法医,也就是我啦,一个学医不精且内向的Boy,在过去相亲999场无一成功的光环背景加持下,不知道谁会是第1000个幸运儿,尽管感情之路坎坷崎岖,我依然相信爱情是十分美好的事情,但前提是和相爱的人走入婚姻。关于婚姻的不幸,往往源于最初的将就。

又到周末了,开心ing~,听同事说附近新开了一家蛋糕店,尤其是菠萝包特别好吃。门前排队的人潮络绎不绝,延伸到街角,车水马龙的景象足以让人停下脚步。门口的招牌上写着“HTTP缓存蛋糕,零糖零卡减肥必备”,明显吸引着众多美食爱好者。店门口的空气中弥漫着香甜的味道,让人垂涎欲滴,想必这种蛋糕不会让人失望。队伍中,我是最后一个,过了一会有个女孩排在我的后面,我假装系鞋带,用余光偷偷瞄了一眼,还挺好看。没多久,终于排到我了,但只剩一个菠萝包了,女孩失落的咽了咽口水,随即转身离开.....

这时该我出场了,潜意识喊了一声:小姐姐,分你一半吧!我们一起吃着那个惊喜的菠萝包,暂时忘记了自己是陌生人的事实。两个人聊个不停,发现自己竟然有着许多相同的兴趣爱好,比如都是热爱旅游的人,并且都很喜欢在路上尝试各种当地美食。

在这段难得的聊天时间中,我得知女孩叫铁锤妹妹,我还向铁锤推荐了一款旅游软件,用于提醒必要的行程和路线。铁锤妹妹感到十分惊喜,因为她一直在寻找这样一个软件,而且这个软件对于她接下来的出行计划非常有帮助。

第二个阶段的决定因素叫多巴胺,也就是我们最熟知的快乐因子,看一本你喜欢的书,多巴胺可以分泌到30%,吃顿美食可以分泌到60%,当遇到一个你喜欢的人,多巴胺就会分泌到100%,如果和喜欢的人发生了肢体接触,多巴胺的分泌可以达到200%,所以说,爱情带来的快感是没有替代品的。

在菠萝包吃完之后,两位同行了书店,聊着彼此的喜好和偏好。铁锤指着某一本书问:“你沉迷于这个世界吗?”我笑了笑说:“我沉迷于你啊。”铁锤也感觉两个人之间产生了不一样的化学作用,她一边脸红一边扭头转向了别处。

过了不久,我们分别辞别,各自回家。铁锤在回家途中,打开了旅游软件,体验了一下刚刚被推荐的导航功能,感觉十分方便,又想到“缓存”,觉得这个软件的加入就像http缓存协议一样,可以为进一步的出游计划省去大量时间和精力。他心里想着,或许时间和经验不够,但是只要有个好的工具,就可以突破现有的限制,去到更远的地方和更多的场景。

进入第三个阶段,也就是让一段关系被确定下来的关键激素,去甲肾上腺素,这个激素支配着你的身心,让你强烈渴望与这个人发生肢体接触和亲密关系。

HTTP 缓存协议和我们之间的相识有许多相似点。就像我们一样,HTTP 缓存协议可以缓存数据并在下一次请求时使用,从而节省时间和资源。如果我能成为你的缓存,我们也可以更快地交流和更好地了解彼此。而且,就像 HTTP 缓存协议中的过期时间一样,我们需要不断地更新自己,以保持新鲜和有趣。

那为什么需要缓存呢?不缓存行不行‍♂️?缓存的主要目的就是减轻服务器处理压力,你(浏览器)自己有就用自己的,不要经常来烦我(服务器)。就像法医跟铁锤妹妹一样,都喜欢吃菠萝包,那我们可以买一些放到冰箱存着

缓存的基本原理

缓存的基本原理还是挺简单的,大家都知道铁锤妹妹特别喜欢吃菠萝包,由于蛋糕店挺远的,所以铁锤妹妹买了一些存到冰箱,想吃就去冰箱拿,不用每次想吃都跑到蛋糕店买,跑来跑去也很累的。

画个简图:

image.png

当冰箱里没有菠萝包的时候,铁锤妹妹会去蛋糕店购买菠萝包,购买的过程表示客户端第一次向服务器发出请求,结账付钱的过程表示蛋糕店正在打包,也就是服务器正在处理请求的过程,随后服务器会给客户端一个响应,这个响应包含很多东西,至于都有什么,后面会说到。

铁锤妹妹买完菠萝包后,放入冰箱里保鲜(加入缓存),等下次想吃的时候(后续请求),再从冰箱(缓存)里拿,但是食品都是有一个保质期的,当有一天过期后,铁锤妹妹会问问蛋糕店老板,你这菠萝包还能不能吃?如果老板说还能吃,铁锤乖乖回家继续吃,如果不能吃,则从新发起购买请求,买点新的回去,继续存冰箱。

我再总结一下这个流程:当客户端(一般指浏览器)向服务器发送一个请求的时候,服务器会给客户端响应一些东西,服务器为了节省自身的压力,会在响应添加一些命令,让浏览器缓存这些文件,浏览器将文件缓存后,如果之后需要这些文件,则会从缓存拿,不会再次发送请求,但是这些缓存不是一直都有效的,到了过期时间后,浏览器会问一下服务器,文件过期了,现在还能用吗?如果服务器回答说:可以继续用,那浏览器就继续用呗

来自服务器的内心独白

当客户端发出一个GET请求到服务器,服务器可能会这样想:你请求的这个资源我很少变动,你干脆缓存起来吧!以后就不要再来烦我了,那什么样的资源文件会很少变动呢?像那些图片、CSS、JS等资源文件。那它是怎么告诉客户端将这些文件缓存起来呢?为了实现心中这美好的愿望,服务器会在响应头中加入以下内容:

carbon.png

这个响应头中包含了如下信息:

  • Cache-Control: max-age=31536000

    我希望你可以把这个资源缓存起来,缓存时间为31636000秒(365天)

  • Date: Thu, 07 Jul 2022 21:35:20 GMT

    我给你响应这个资源的服务器时间是格林威治时间2022-07-07 21:35:20,如果缓存的时间是365天,那就是在此时间上加上365天

  • Etag: W/"3be5f29ac3de039909660e93e1ca5912"

    这个资源编号是 W/"3be5f29ac3de039909660e93e1ca5912"

  • Last-Modified: Tue, 05 Jul 2022 15:09:26 GMT

    这个资源上一次修改时间是格林威治时间 2022-07-05 15:09:26

通过在响应头中添加这些信息,服务器的美好愿望就传递给了客户端,如果客户端是其它应用程序,那它压根不会理会服务器的愿望,你的愿望跟我有毛关系,但是恰好这里的客户端是一个浏览器,服务器和浏览器是形影不离的好基友。

那当浏览器接收到来自服务器的美好愿望该做些什么呢?

  • 浏览器会将这次请求得到的响应体缓存在本地文件中
  • 浏览器会记录这次请求的请求方法和请求路径
  • 浏览器会记录本次缓存时间是31536000秒
  • 浏览器会记录服务器响应时间是格林威治时间2022-07-07 21:35:20
  • 浏览器会记录服务器给予的资源编号是W/"3be5f29ac3de039909660e93e1ca5912"
  • 浏览器会记录上一次资源修改的时间是格林威治时间 2022-07-05 15:09:26

浏览器的记录非常重要,它为将来要不要请求服务器提供了依据。我们在浏览器中可以很清楚看到被缓存到磁盘的文件(disk cache),取文件的时候耗时非常短

image.png

接着我们的图可以这样画

image.png

来自客户端的内心独白

当客户端有了缓存之后,再次请求GET /index.js的时候,它突然想起一件事情,我所需要的东西在不在缓存里呢?那又是如何判断的呢?

判断过程如下:

  • 缓存中是否有匹配的请求方法和路径
  • 缓存中如果存在,那该缓存资源是否在有效期内?

看个简图:

image.png

这张图就是判断流程,当准备请求服务器的时候,首先会判断有没有匹配的缓存,如果没有,那就是普通的一次请求。如果存在缓存,接下来就要判断缓存有没有过期,如果没有过期,那就不需要请求服务器了,直接使用缓存的内容。如果过期了,浏览器并不会删除这个缓存,虽然过了很久,但是浏览器依然抱着一丝希望,因为缓存虽然过期了,但是文件本身并没有改变,这时浏览器会询问一下服务器,这个文件到底变没变啊,没变那就继续使用,这种带缓存的请求我们一般称为协商请求

接下来,图会变成这个样子哦:

image.png

缓存有效

当浏览器发现缓存有效时,压根是不会请求服务器的,直接使用缓存的内容,即使处于无网络环境下,依然可以正常浏览已经缓存的内容。缓存极大减轻服务器的压力,但是当服务器更改了资源后,浏览器是不知道的,只要缓存有效,就会直接使用缓存。

缓存无效

当浏览器发现缓存已经过期后,它并不会简单的把缓存删除,而是抱着一丝希望,询问服务器,缓存还能用吗?然后浏览器会发出一个带缓存的请求,我们一般称为协商请求,所谓的带缓存的请求,无非是加入了以下请求头:

carbon (1).png

  • If-Modified-Since: Tue, 05 Jul 2022 15:09:26 GMT

亲爱的,你曾经告诉过我,这个资源上一次修改时间是格林威治时间 2022-07-05 15:09:26,不知道在这个时间之后有变动吗?

  • If-None-Match: W/"3be5f29ac3de039909660e93e1ca5912"

宝~,我记得你之前跟我说过,这个资源编号是 W/"3be5f29ac3de039909660e93e1ca5912" ,请问这个资源编号现在发生改变了吗?

总结起来就一句话:你快告诉我这个资源到底变了没?之所以要发这两条消息,是为了兼容不同的服务器,因为有的服务器只认If-Modified-Since,而有的服务器只认If-None-Match,有些两个都认。目前有很多服务器,只要发现If-None-Match存在,就不会去看If-Modified-SinceIf-Modified-Since是http1.0版本规范,If-None-Match是http1.1的规范

此时,又把问题抛给了服务器,我们来看看服务器又是如何表演的

当浏览器询问服务器:亲爱的,你的心到底变没变?服务器会产生两种情况

  • 宝,我变了,我们不合适:缓存已经过期
  • 我没有变,我依然爱你:缓存依然有效

如果缓存已经过期,服务器会再次给予一个正常的响应(响应码200,带响应体),同时会附带上新的缓存指令,这就回到了前面说的来自服务器的内心独白,客户端会重新缓存新的内容。

如果服务器觉得缓存依然有效,那么服务器会通过一种非常简单的方式告诉浏览器:

  • 响应码为304 Not Modified
  • 没有响应体
  • 响应头会带上新的缓存指令

这样一来,就相当于告诉浏览器:你的缓存依然可以继续使用,我给你一个新的缓存时间,你那边更新一下就行。然后,浏览器继续愉快地使用缓存了。

通过这种方式,可以最大程度上减少网络传输,因为如果资源还有效,服务器就不会传输消息体。

经过以上流程,我们的图就会变成这样:

image.png

补充一些知识点

Cache-Control

Cache-Control在上面已经说过了,它是服务器向浏览器响应的一个消息头,它提供了一个max-age用于指定缓存时间。实际上它还有其他值可以选择。

  • public:表示服务器资源是公开的,对于浏览器来说并没有什么意义,因为大家看到的东西都是一样的,没有变化,也许在某些场景下有用。
  • private:表示服务器资源是私有的,比如某个服务器资源,每个用户看到的都不一样,http协议中很多时候都是客户端或者服务器告诉另一端详细的信息,至于另一端用不用完全自己决定。
  • no-cache:这个值看起来字面意思是不缓存的意思,其实不然,它会告诉浏览器,你可以缓存这个资源,但是不要直接使用它。当你缓存后,每一次请求都需要附带缓存指令,每一次请求都需要问一下才行,相当于每一次都是协商缓存
  • no-store:告诉浏览器不要缓存这个资源,后面每一次请求都按照普通请求进行,
  • max-age:这个就不说了吧

Expires

Expires是很早之前的一个字段,在http1.0版本中通过Expires响应头指定过期的时间点。现在都是使用Cache-Control:max-age来指定过期时间,有些服务器为了兼容其它浏览器也是会加上Expires

image.png

缓存时间的有效期

image.png

当浏览器收到来自服务器的响应之后,首先它会检查是否有max-age,如果有,继续看下是否存在Date字段,如果也有,那么缓存过期时间就是 Date + max-age,如果没有Date字段,那么过期时间就是当前客户端时间 + max-age

如果没有max-age,那么会继续检查是否有Last-Modified字段,如果没有,就不需要缓存了,如果有,那么缓存过期时间过期为(当前客户端时间 - Last-Modified)/ 10 

Pragma

Pragma是http1.0版本的消息头,当该消息头出现在请求中时,是为了告诉服务器不需要缓存,正常请求就行。
然而在http1.1中使用Cache-Control:no-cache来表示。当我们在调试工具中勾选Disable cache时,就会显示出Pragma字段

image.png

最后

如果本篇文章对你有所帮助,或者你有什么疑问,欢迎在评论区留言,我一般看到都会回复的。大家点赞支持一下啊~,点击链接即可关注 法医

你可能感兴趣的:(前端后端http)