开始前的碎碎念
最近加班真的很严重,组里同事们都已经苦不堪言。业务交付压力非常大,根本没时间去磨练本领,学习技术。真的很讨厌这种没有成长的日子,每天被业务需求赶着跑。每天下班之后,本来应该用于提升自我的时间也被压榨用来写业务代码。
希望组里能早日摆脱现状,不然就只能润了
很多人应该都听过http缓存,也是比较常问的面试题吧。还记得我当时什么也不会,刷面经的时候就看到什么http状态码里的304,然后就顺着去搜了一下,搜到了什么协商缓存,看了一下,看的云里雾里。主要还是当时真的欠缺太多基本知识了,搜到的博客里面又都没讲这些基础的点。所以我这次想来通俗的讲一讲,http缓存。注意,本文中所指的服务器,绝大部分都是前端的,返回给你html文件等等的那个服务器,而不是部署着接口的后端服务器。
为什么需要http缓存
理解静态资源
我们都知道,访问一个网站,浏览器会向网站服务器发送很多http请求,去请求html文件,css文件,js文件等等。这些文件都是静态资源。静态资源,其实就是服务器上的文件罢了,不经常变化。你写一个网站的前端代码,写好了部署上去,就不变了。除非你重新部署,上面的文件才变。不像你请求接口,去查数据库里面的数据,那是经常变化的。
就因为静态资源不常变,所以我们可以把它们缓存起来。这样下次再请求的时候,缓存没过期的话,就可以直接从缓存里面读静态资源,会比从服务器再收一次静态资源快上很多。
注意:http缓存通常只针对get请求。这也很合理,因为浏览器访问网站,获取静态资源时,发送的请求都是get。至于你访问接口,就由你自己控制了。我的评价是接口都可以用post访问。
如何判断缓存是否过期
http缓存有两种:强缓存和协商缓存。流程省流:先强缓存,再协商缓存,再重新向服务器请求。
省流
通俗来说,浏览器向服务器请求静态资源的时候,服务器会说,你多久之内不要再来问我这个问题。于是这个时间内,每当浏览器需要用这个资源时,都会用第一次服务器给他的那份,这就是强缓存。
过了这个时间以后,强缓存失效了。浏览器会再去问服务器要这个资源,但是它问的时候会带上两个问题:
- 你上次给我的东西,哈希值是这个,你看看变了没
- 你上次给我的东西,是某个时间更新的,你看看还是不是最新的
服务器根据这两个问题来判断,浏览器的缓存还能不能用。如果能,服务器返回给浏览器的http状态码是304,意思就是和上次一样,我就不再给你一份了。如果不能,则服务器会重新发一份静态资源给浏览器。这就是协商缓存
强缓存
强缓存就是指,你第一次请求静态资源的时候,服务器返回给你的response header里面如果带下面的两个字段之一:expires或者cache-control,则浏览器会用强缓存规则判断缓存是否过期。expires是直接写死的过期时间,下次再发请求的时候,取当前时间和过期时间比较,来判断是否过期。而cache-control下面的max-age字段则是指定了一个时长。下次请求的时候,会看距离上次过了多久,比较时长来判断是否过期。
expires来自http1.0,cache-control的max-age来自http1.1 。expires的缺陷是没考虑时区问题。客户端和服务端的所处时区不一致时,expires是服务端所在时区的时间,而客户端会把它当成是自己所在时区的时间。
看到这里我们可以知道,强缓存的过期时间是服务器那边人为控制的,人为指定了这个缓存能有效多久。如果缓存没过期,我直接问都不问服务器。所以这个时间设定不宜太长,不然即便这些静态资源被更新了,用户也拿不到,因为用户一直在读本地的缓存。
协商缓存
当强缓存失效的时候,浏览器还会再挣扎一下,走协商缓存。前提是第一次返回的静态资源的响应头里面有下面两个字段之一:etag或者last-modified。etag可以理解为是这个静态资源的哈希值,内容变化会导致etag的变化。last-modified是这个静态资源上次被修改的时间。
等到第二次请求这个静态资源时,浏览器会向服务器发一个请求,这次请求头里面的if-none-match的值为上一次的response的etag,if-modified-since值为上一次response的last-modified。服务器收到这个请求,会再去看一下服务器上的静态资源,它的etag和last-modified,然后自己根据浏览器传过来的etag和last-modified,判断一下浏览器那边的缓存是否还能用。如果还能用,也就是没过期,就返回一个http code304。如果不能用,就返回最新的静态资源过去(当然http code是200)。
至于服务器如何根据etag和last-modified判断,这个是看服务器具体怎么实现的,各大框架应该都已经有现成的实现了。反正单独看两个字段的话,肯定是比较etag是否一致,和last-modified值是否相同了。但是二者的优先级,是依靠具体实现的。etag的准确度肯定更高。如果在last-modified的最小时间精度内,文件被修改了多次,last-modified是区分不出来的。而且无谓的修改也会导致last-modified的改变,即使修改并没有改动到文件的内容。所以通常建议以etag为准。