- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
HTTP缓存相关的问题好像是前端面试中比较常见的问题了,上来就会问什么cache-control字段有哪些,有啥区别啥的。嗯……说实话,我觉得至少在本篇来说,HTTP缓存还算不上复杂,只是字段稍微多了点,大家用心记一下就好啦.
缓存的概念,其实在你访问互联网中的任何资源其所产生的任何链路中的每一个节点几乎都会进行缓存,整个缓存体系和细节十分复杂。比如浏览器缓存,服务器缓存,代理服务器缓存,CDN缓存,等等等等.
但是缓存又十分重要,不可缺少,为啥这么说呢?由于HTTP请求的链路漫长,环境复杂,把一些必要的信息在关键的节点进行缓存,下次请求的时候可以尽可能的复用数据,就可以节省一部分资源的消耗,减少HTTP请求-应答的成本,节约带宽,加快响应速度.
那么,基于请求-应答模式的特点,缓存大致可以分为服务器缓存和客户端缓存,而服务器缓存经常与代理服务关联在一起,所以,我们今天讲的缓存,其实主要聊的就是客户端缓存,也就是浏览器缓存。下一篇,下下篇就会讲代理和代理缓存。嗯……代理其实也不复杂,但是往往两个东西组合起来的就会复杂一些.
那我们就来看看浏览器是咋缓存的吧.
假设,现在没有缓存,我们想象一下获取资源的方式是什么样的?客户端请求资源,服务器返回资源,等下一次想要获取同样资源的时候,哪怕服务器的资源并没有更新,还是要重新走一遍网络请求,然后服务器返回资源的完整链路.
那,如果有了缓存,在客户端第一次获取到请求的资源后,把资源缓存到本地,下次再去请求的时候,发现本地有这个资源,直接拿来用就好了,完全不用去走网络请求。有缓存的简易流程大概是这样的:
我们仔细的阅读一下这个简单的缓存资源请求流程,发现其中有几个重要的节点。首先,服务器在返回该资源时, 要标记该资源的有效期 。然后,浏览器初次请求肯定是没缓存的,再次请求的时候,它要根据该资源的有效期来判断下一步该怎么办。OK,我们再简单一点,如果我们试图去获取缓存资源,其实是要看服务器的标记的.
那么换句话说, 服务器标记缓存资源,浏览器会验证该缓存资源的标记 .
这个字段想必大家非常熟悉了吧,就是服务器用来标记资源缓存有效期的头字段。我们可以这样来标记资源的有效时间:
Cache-Control: max-age=
30
啥意思呢,就是该资源的有效期是30秒。这是一个相对时间, 时间计算的起点是报文创建的时刻,也就是Date头字段的时间,是指资源离开服务器的时刻 ,而不是客户端收到报文的时候,换句话说,假设我们设置的时间是5秒,但是链路请求很长,花费了4秒的时间,那么缓存对于浏览器的有效时间只是1秒。那你可能会说,就这一秒有啥用啊~~假设你网站的访问量特别大,每秒有上百万的访问,那你可以想象到这仅仅一秒的时间能节省服务器多大的压力了吧。当然,只是举个极限的例子~ 。
除了max-age这个最常用的属性以外,还有三个属性可以更精确的指示浏览器如何使用缓存:
cache-control的这几个字段的差别十分细微,大家要稍微认真记一下.
我们学了四个Cache-Control头字段的属性,我们来看张图,巩固一下这些细微的差别:
我们来过下整张图的流程,首先浏览器要通过no-store属性判断该资源是否允许缓存,如果允许缓存,那么继续判断是否在 使用缓存前去验证 ,需要验证的话就直接判断max-age,否则还要再去判断must- revalidate属性, 缓存失效后是否需要验证.
我们刚刚学习了Cache-Control头字段,并且学习了服务器是怎么控制该字段的相关属性的。不仅仅是服务器可以控制缓存,客户端也可以控制缓存,客户端是怎么控制的呢?
当你点击浏览器的刷新按钮的时候,实际上,浏览器就在HTTP请求中夹带了"Cache-Control:max-age=0",之前说过,max-age是生存时间,纪录的是从服务器生成的那一刻的有效期,而浏览器本地的资源,肯定不可能是0,所以当浏览器加上了max-age=0的时候,每次都会向服务器请求最新的资源。而当你使用Control+F5强制刷新的时候其实是浏览器发了一个“Cache-Control: no-cache”。基本上和max-age=0差不多一样的效果,但是含义肯定是不一样的,就看服务器要怎么理解和处理不同的字段.
那么什么时候缓存才能派上用场呢?当我们点击浏览器的前进后退按钮的时候,就会直接从缓存中获取数据,另外,重定向的时候,也可能会使用到缓存。那这两类操作有啥区别呢。其实本质上来说,就是前进、后退、跳转这样的操作,浏览器不会私自加上Cache-Control字段,并且会清空If-Modified-Since 和 If-None-Match字段(后面会说条件请求),所以就会检查缓存,直接利用之前的资源,不再进行网络通信.
我们可以在稍后的例子中试一下~ 。
仅仅只是Cache-Control字段,只能做到刷新数据,不能很好的利用缓存数据,由于缓存数据可能会失效,所以每次使用缓存前还必须去服务器验证一下。有点麻烦~ 。
那咋整呢?我们可以先发一个HEAD请求,或许服务器资源的一些基本信息,然后和缓存的数据做比较,如果没有改动就使用缓存,否则呢,就去服务器获取最新的资源.
但是这样的两个网络请求成本太高了,所以HTTP就定义了一些If开头的“ 条件请求 ”字段,专门用来验证资源是否过期,把两个请求合并到一个请求中,验证的职责也交给服务器,客户端只要坐享其成就可以了.
条件请求一共有五个字段,我们最常用的只有“ if-Modified-Since ”和“ If-None-Match ”这两个。需要第一次请求的时候,服务器预先提供“ Last-modified ”和“ ETag ”,当第二次请求的时候就可以带上缓存里的原值,验证资源是否是最新的.
如果资源没有变化,那么服务器返回个304,更新下资源的有效时间,使用缓存就可以了.
Last-modified很好理解,就是最后一次修改文件的时间。那ETag是啥呢? ETag 是“实体标签”(Entity Tag)的缩写,是资源的一个唯一标识,主要是用来解决修改时间无法准确区分文件变化的问题.
比如,文件的修改时间是秒级甚至更短的,所以一秒内的新版本是无法区分的,再比如,一个文件定期更新,但有时内容没有变化,用修改时间就会以为发生了变化,发送给客户端以为是新的资源,浪费带宽.
使用ETag就可以精确的识别资源的变动情况,让浏览器更有效地利用缓存.
ETag还有强弱之分.
强 ETag 要求资源在字节级别必须完全相符,弱 ETag 在值前有个“W/”标记,只要求资源在语义上没有变化,但内部可能会有部分发生了改变(例如 HTML 里的标签顺序调整,或者多了几个空格)。至于是强还是弱,其实是由服务器自主决定的。弱也可以强,强也可以弱.
条件请求里其他的三个头字段是“If-Unmodified-Since”“If-Match”和“If-Range”,其实只要你掌握了“if-Modified-Since”和“If-None-Match”,可以轻易地“举一反三”.
我们先搞个max-age的小例子,看看缓存能否生效:
res.setHeader("Cache-Control", "max-age=20");
就很简单,我们可以看到在响应头中返回了我们设置好的缓存字段:
大家还可以自己尝试设置no-store,no-cache等字段。当你设置了no-store属性后,你会发现,哪怕使用浏览器的前进,后退按钮,每次也是重新从服务器获取资源,但是no-cache和max-age则会使用缓存.
简单的例子就这样啦~ 。
本篇到这里就结束啦~我们稍稍回顾一下,都学了哪些内容,其实就一个字段Cache-Control,并且稍微涉及到了一点关于浏览器可能会夹带的私货是怎样的。并且我们还学习了条件请求以及强弱Etag,大家要着重了解下。然后呢,本篇没有问题,但是有个遗留的小例子我没写,就是条件请求的例子。大家可以参照我上面的小例子,试着在 这里 玩一下条件请求.
好啦~下一篇,我们来学下代理~ 。
。
最后此篇关于真正“搞”懂HTTP协议10之缓存控制的文章就讲到这里了,如果你想了解更多关于真正“搞”懂HTTP协议10之缓存控制的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
HTTP缓存相关的问题好像是前端面试中比较常见的问题了,上来就会问什么cache-control字段有哪些,有啥区别啥的。嗯……说实话,我觉得至少在本篇来说,HTTP缓存还算不上复杂,只是字段稍
代理,其实全称应该叫做代理服务器,它是客户端与服务器之间得中间层,本质上来说代理就是一个服务器,在HTTP的链路中插入的一个中间环节,就是代理服务器啦。所谓的代理服务就是指:服务本身不生产内容,
我们在前两篇的内容中分别学习了缓存和代理,大致了解了缓存有哪些头字段,代理是如何服务于服务器和客户端的,那么把两者结合起来,代理缓存,也就是说代理服务器也可以缓存,当客户端请求数据的时候,未必一
在前面的章节,我们把HTTP/1.1的大部分核心内容都过了一遍,并且给出了基于Node环境的一部分示例代码,想必大家对HTTP/1.1已经不再陌生,那么HTTP/1.1的学习基本上就结束了。这两
我们前一篇学习了HTTP/2,相比于HTTP/1,HTTP/2在性能上有了大幅的改进,但是HTTP/2因为底层还是基于TCP协议的,虽然HTTP/2在应用层引入了流的概念,利用多路复用解决了队头
前面我们花了很大的篇幅来讲HTTP在性能上的改进,从1.0到1.1,再到2.0、3.0,HTTP通过替换底层协议,解决了一直阻塞性能提升的队头阻塞问题,在性能上达到了极致。 那么,接下
上一篇噢,我们搞明白了什么是安全的通信,这个很重要,特别重要,敲黑板!! 然后,我们还学了HTTPS到底是什么,以及HTTPS真正的核心SSL/TLS是什么。最后我们还聊了聊TLS的实
经过前两章的学习,我们知道了通信安全的定义以及TLS对其的实现~有了这些知识作为基础,我们现在可以正式的开始研究HTTPS和TLS协议了。嗯……现在才真正开始。 我记得之前大概聊过,当
这一篇文章,我们核心要聊的事情就是HTTP的对头阻塞问题,因为HTTP的核心改进其实就是在解决HTTP的队头阻塞。所以,我们会讲的理论多一些,而实践其实很少,要学习的头字段也只有一个,我会在最开始
我们在之前的文章中介绍HTTP特性的时候聊过,HTTP是无状态的,每次聊起HTTP特性的时候,我都会回忆一下从前辉煌的日子,也就是互联网变革的初期,那时候其实HTTP不需要有状态,就是个浏览页面
前面几篇文章,我从纵向的空间到横向的时间,再到一个具体的小栗子,可以说是全方位,无死角的覆盖了HTTP的大部分基本框架,但是我聊的都太宽泛了,很多内容都是一笔带过,再加上一句后面再说就草草结束了。
大家好,我是煎鱼。 在 Go 语言中总是有一些看上去奇奇怪怪的东西,咋一眼一看感觉很熟悉,但又不理解其在 Go 代码中的实际意义,面试官却爱问... 今天要给大家介绍的是 SliceHead
我是一名优秀的程序员,十分优秀!