聊一聊http缓存(强缓存与协商缓存)

191 阅读4分钟

http缓存网上的文章很多了,最近看了一些,结合自己的理解,作一点总结。

1 强缓存

所谓强缓存,可以简单的理解为强制缓存,它规定在一定的时间内客户端如果再次发送请求,则直接走缓存资源。同时服务端返回200状态码。(强缓存只发生在至少第二次请求中)

那问题来了?我客户端向你服务端发送请求,你为啥要强制我走缓存呢?那浏览器和服务端肯定有一些约定。

在很早之前,http1.0时代,浏览器和服务器之间就约定了一个规则:

服务器:"老哥,你以后如果再http请求头里带上了expires,那我就计算一个时间,时间过期了,我再给新的资源给你"

浏览器:"好的,老铁!" 服务器:"那好,咱们先演练下,现在是2022/12/24:9:00,在2022/12/24:10:00点前如果你请求我,你就直接给你返回200,你去缓存找资源了哈"

浏览器:"好的哥,http(10 Dec 2021 10:00 GMT)" 服务器:"老哥稳!!"

看似美好的过程,其实这中间隐藏着bug,expire时间是服务端定的。它是一个绝对时间,但是对于用户来说,他本机的时间是可能改的,和服务端可能并不一致。这样就会导致一个问题:用户的机器时间是2000年,而服务器的时间规定的时间是2022/12/24/10:00到期。问题大了。

为了解决这个大bug,后来http1.1中服务器和浏览器再次做了规则的修改。

服务器:"老哥,你以后如果再http请求头里带上了cache-Control,那我就计算一个时间,时间过期了,我再给新的资源给你" 浏览器:"好的。老哥。你这计算时间不会又像上次那样吧?搞个绝对时间,可把我害惨了" 服务器:"老铁,相信我。这次我改了"

浏览器:"好的,老铁!"

服务器:"那好,咱们先演练下,现在是2022/12/24:9:00,在1个小时之内如果你请求我,你就直接给你返回200,你去缓存找资源了哈"

浏览器:"好的哥,http(cache-control:max-age=25920000)" 服务器:"老哥稳!!"

浏览器:"老哥牛逼啊!!"

通过相对时间的设定。服务器就能准确计算过期时间。从而避免了之前expires导致的问题。这两个标识可以同时设置。但是cache-control的优先级更高些。

**协商缓存

协商缓存可以理解为客户端向服务器发送请求,服务器需要对比客户端缓存的文件和服务端是否一致,如果一直则返回304状态,如果文件就返回新文件。

那问题来了? 服务器如何知道客户端缓存的文件和服务端的一致呢? 为了解决这个问题。在很早之前,有一个方案,就是服务器根据文件最后修改得时间作为参考

客户端 -----------------------(第一次请求)----------------------------------服务端

    <--------lastModify:time(第一次请求服务器给客户端返回)----------------------
    -----------if-Modify-Since:(time)(第二次请求)----------------------------->
    

基本流程如上图:
客户端第一次请求以后,服务端会给客户端一个标识lastModify,它的值是一个时间(也是一个绝对时间,它精确到秒), 而客户端第二次请求服务端的时候,在http请求头里加上if-Modify-Since:它的值就是上次服务端lastModify给的时间。如果这两个时间相等。就表示没有改动。那 就直接走缓存吧。

这个思路看似可行。实际上也隐藏着一个bug:如果我在1s内频繁改动。你再根据最后修改时间来做匹对判断就不对了吧?

所以在http1.1中。浏览器和服务端又把规则做了改进:

服务器:"老哥,你以后如果再http请求头里带上了Etag,咱不根据最后修改时间来了,那玩意不靠谱。我在这边通过生成一个摘要返给你。你第二次请求的时候带上这玩意,我在服务端重新比较文件生成的值和你带上的值做比较,如果一致就说明没有改动,我返回你304,你直接去走缓存吧"

浏览器:"好的。老哥。我咋带给你呢?" 服务器:"老铁,你在http请求头里通过if--None-Match:value(我通过etag给你的值)"

浏览器:"好的,老铁!"

服务器:"测试一波,兄弟!!"

浏览器:"可以啊。奥利给...牛逼啊!!"

客户端 -------(1第一次请求)-------------->服务端

     <----Etag :hashvalue(1第一次请求)---------
     
     ------------(if--None-Match:hashvalue)----第二次请求--> 
                                               (重新生成摘要匹配要请求的文件和if--None-Match的值是否相等)

这两种策略可以同时使用。但是etag的优先级会更高一些