文章目录
1 什么是HTTP缓存?
缓存一词应该大家都不陌生,最基本的功能之一就是提高我们的访问速度。不管是我们较为熟悉的计算机组成中的Cache,还是今天我们要聊的HTTP缓存,提速的具体方式就是提前先把资源由原来的地方放到一个容易拿到的地方。
这样做会提高我们访问浏览器的速度,节省我们的流量,减轻服务器的压力,我们打开网页的时候“嗖~”的一下就打开了,这岂不是很爽?
今天的这篇文章主要是针对HTTP缓存,简单来说就是根据HTTP头部信息进行的缓存。其实除此之外,为了使到我们能够“嗖~”的一下打开网页,web前端部分还会有一些其他的缓存机制协配合去打团战。先上图吧,目前想到了这些,之后再慢慢补充。图中的内容之后的文章都会一一介绍~
那么问题来了:
- 哪个地方容易拿到?
答:当然是本地啊,不过本地也分两个地方:一个是在本地内存中,主要是那些刷新频率比较高的资源,但是又不能都放在内存中,毕竟内存资源还是很珍贵的;那另一部分就会存入本地的磁盘内,这部分资源存储的时间会久一些,容量也会大一些。 - 浏览器怎么知道要去本地拿资源呢?
答:其实这和浏览器的工作机制相关,也就是说浏览器在向服务器请求资源之前,都会去本地看一下,如果能用的话就不费劲去请求了,直接拿来便是。 - 咋看能不能用啊?
答: 首先,原理上来说不能用的的原因只有一个就是这个资源被更改了,不能再用旧的了。也是就是说我们既要浏览器加载的快,不能老去找服务器,但是一旦服务器有更新还得屁颠屁颠的跟上!毫无尊严可言!由此便衍生出了一系列规则,构成了浏览器的缓存机制。
2 HTTP缓存分类
HTTP缓存主要由两部分组成:硬缓存、协商缓存。
2.1 硬缓存
2.1.1 大体思想
浏览器和和服务器对每个缓存资源先商量一个 “保质期” ,被浏览器缓存的资源在“保质期”内是有效的,也就是说在这段“保质期”里,浏览器不需要服务器的同意,直接就可以用本地缓存去实现“嗖嗖嗖~”。
2.1.2 具体实现
在HTTP/1.0中,主要是通过设置Expires字段的值来确定这个“保质期”,也就是图片中的“明天之前”例如:
Expires:Thu, 03 Dec 2020 23:18:59 GMT
但是他会受客户端时间改变的影响,往往会出现一些差错,所以一般是在要考虑兼容HTTP/1.0时才会使用。
在HTTP/1.1中做了改进,我们通过设置Cache-control字段来实现“保质期”以及一些其他内容,例如:
Cache-control的常用值(可多个组合使用):
public //表示可以被客户端和代理服务器缓存
private //表示只可以被客户端缓存
max-age=66 //66秒后资源过期,对应图片中的"三天之内"
no-cache //只是嘴上说“不要缓存”,实际上还是会缓存,只是用之前要协商一下
no-store //这次是真的不会存
2.2 协商缓存
2.2.1 大体思想:
这个也很好理解,我们刚才所说的“保质期”总会有过期的时候,那么缓存协商就是来解决资源过期之后的方法。浏览器就要去问服务器:我现在缓存的东西还能用么?商量一下,如果能用就继续用,不能用就请求一个新的。他也有两种表示方式:
2.2.2 具体实现:
当如下情况,客户端二次请求时会与服务器进行协商:
- 没有Cache-Control和Expires
- Cache-Control和Expires过期
- 设置no-cache
如果服务器端的资源没有修改,那么就会返回304状态码,表示可继续应用缓存。如果数据有更新就会返回200状态码,服务器就会返回更新后的资源并且将缓存信息一起返回。
在HTTP/1.0中,我们使用的是Last-Modified/If-Modified-Since相配合的方式:
- 第一次请求服务器给客户端一个GMT格式的时间(这个时间是就是发送时刻的Last-Modified)
- 当需要协商时,客户端向服务器发送这个GMT时间,也就是If-Modified-Since的值
- 服务器将收到的If-Modified-Since的值和最新的Last-Modified做比较,若无变化则返回304,有变化返回200和新的Last-Modified
但是这种方式存在着一些缺点,例如:
- 负载均衡的服务器,各个服务器生成的Last-Modified可能有所不同
- GMT 格式有最小单位,例如,如果在一秒内有更改将不能被识别
在HTTP/1.1中,我们对上述问题做了改进,使用的是ETag/If-None-Match相配合的方式:
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识序列,当资源有变化时,Etag就会重新生成。具体流程和Last-Modified/If-Modified-Since类似。
- 第一次请求服务器给客户端一个ETag(这个标识是就是发送时刻的ETag)
- 当需要协商时,客户端向服务器发送这个ETag,也就是If-None-Match的值
- 服务器将收到的If-None-Match的值和最新的ETag做比较,若无变化则返回304,有变化返回200和新的ETag
这种方式的缺点:
- ETag的生成需要消耗一定时间,效率不及前一种方法
3 当我们在地址栏输入URL的时候浏览器发生了什么?
这是一道非常经典的前端面试题,如果要详细的回答这个问题,可能要写一篇超级长文了,那么今天我们先从HTTP缓存的角度说一下这个问题,在之后的博客里我还会列出这个问题,我们再一点点丰富回答!
我们上面简单介绍了一下HTTP缓存的主要组成部分,那么当这些东西都混在一起时,浏览器是如何工作如何区分优先级的呢?先上几张网图~
- 初次请求
- 再次请求
下面我总结一下优先级关系:
- 强制缓存优先于协商缓存
- Cache-Control优先级高于Expires
- Etag/If-None-Match 优先级高于 Last-Modified/If-Modified-Since
注意: 若不设置任何缓存策略,浏览器会有默认缓存机制,通常会取响应头中的 Date 减去 Last-Modified 值的 10% 作为缓存时间
4 事情远没有这么简单!
前后端就这样吵起来了。。。
其实我们可以用过用户的操作来影响浏览器的缓存,进行资源的同步比如,再来个表:
用户行为 | 强缓存 | 协商缓存 |
---|---|---|
地址栏回车 | 有效 | 有效 |
页面链接跳转 | 有效 | 有效 |
新开窗口 | 有效 | 有效 |
前进、后退 | 有效 | 有效 |
F5刷新 | 无效 | 有效 |
Ctrl+F5强制刷新 | 无效 | 无效 |
但是,我们不能寄希望于用户的动作,去达到我们更新资源的目的,应该还有一套更加完善的缓存方案等待着我们去寻找,有很多细节等待着我们去优化,我们还能更快!进而让我们用户的体验更加舒适,接下来的文章我会和大家一起探索哦~