HTTP 缓存机制作为 Web 应用性能优化的重要手段,也是前端面试中经常被光顾的常客。阅读本文,我们主要能了解到http缓存的概念、用途以及如果应用它。
http缓存
浏览器通过网络获取资源缓慢且耗时,一次http请求需要经过三次握手来和服务器建立链接,对于大一点的数据更需要多次往返,因此我们引入http缓存,http缓存主要针如css,js,图片等更新频率不大的静态文件。主要好处如下:
1 加快网页加载速度,提升用户体验
2 减少服务器的负担,提升网站性能
3 减少了冗余的数据传输,节省网络流量和带宽
http缓存主要通过服务端在响应头告诉浏览器是否应该缓存资源、是否强制校验缓存、缓存多长时间等信息。http缓存主要分为强缓存和协商缓存两种。
强缓存
强缓存主要通过响应头中的Expires
或者Cache-Control
两个字段来控制的,用来表示资源的缓存时间
1. Cache-Control: 请求/响应头,缓存控制字段,可以说是控制http缓存的最高指令,可以有多个值,意义也各不相同:
- no-store:禁止缓存,每次请求都要向服务器重新获取数据
- no-cache:也缓存,但是在使用已缓存的数据前,需要发送带验证器的请求到服务器。主要是结合协商缓存使用
-
max-age=x 指定一个时间长度,在这个时间段内缓存是有效的,属于相对时间,单位是s。在
http1.1
版本中使用 - private 只能被单个用户缓存,不能被代理服务器缓存。
- public 表明响应可以被任何对象(发送请求的客户端、代理服务器等等)缓存。
2.Expires: http1.0
的属性,代表资源过期时间,属于绝对时间(时间戳),优先级比max-age
低。由于客户端时间可被修改,和服务器时间可能存在较大差异,因此可能导致缓存混乱
当命中强缓存时,浏览器并不会将请求发送给服务器。此时在开发者工具中返回的状态码为200,但Size列会显示为(from cache)
- from memory cache: 从内存中获取资源,进程被关闭则清空缓存,一般是脚本、图片、字体等文件会存在内存当中。
- from disk cache: 从磁盘中获取资源,进程关闭也不会被清空,一般是css等样式文件会存在磁盘中
资源加载遵循三级缓存原理,即 内存 > 磁盘 > 网络请求。以加载一张图片为例:第一次访问,从服务器加载资源,此时刷新页面,则从内存中读取from memory cache
。关闭掉浏览器后,内存清空,再次打开该网页,在缓存未失效的情况下从磁盘读取from disk cache
。
协商缓存
若没有命中强缓存,则浏览器会将请求发送至服务器。服务器根据http头信息中的Last-Modify
和If-Modify-Since
来判断是否命中协商缓存。具体步骤如下:
- 当第一次请求服务器,服务器响应头会返回一个
Last-Modify
,Last-Modify
是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。 - 浏览器第二次访问服务器,会在请求头中带一个
If-Modified-Since
,就是缓存之前请求时服务端是返回的If-Modify-Since
,服务器收到后,根据资源的If-Modify-Since
和最后修改时间判断是否命中缓存。若命中缓存,此时状态码返回304且不会返回资源和Last-Modify
,表示文件没修改过,还是从本地缓存中去读取。
但是Last-Modify
也存在一些弊端:
- 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
- 某些文件修改非常频繁,比方说1s内修改了N次,而
Last-Modify
只能精确到秒 - 某些服务器不能精确的得到文件的最后修改时间
因此http1.1
又推出了ETag/If-None-Match
。
ETag/If-None-Match返回的是一个校验码。ETag是综合Inode,MTime和Size得到的,可以保证每一个资源是唯一的,资源变化都会导致ETag变化。优先级ETag/If-None-Match
比Last-Modify/If-Modify-Since
更高。现代前端构建工具如webpack
都能自动更新文件hash,每次资源去生成和校验ETag也是一次性能消耗,因此推荐直接设置长缓存时间。
同时,我们对浏览器的不同行为也会对缓存结果造成不同的影响:
用户操作 | Expires/Cache-Control | Last-Modified/Etag |
---|---|---|
地址栏回车 | 有效 | 有效 |
页面链接跳转 | 有效 | 有效 |
新开窗口 | 有效 | 有效 |
前进、后退 | 有效 | 有效 |
F5刷新 | 无效 | 有效 |
Ctrl+F5刷新 | 无效 | 无效 |
总结
为了使缓存策略更完善,因此一般Expires
和Cache-Control
一起使用,甚至强缓存和协商缓存同时使用。当然,http缓存作为一种性能优化手段,带来的好处是不言而喻的。至于具体是使用强缓存还是协商缓存,就需要根据业务自己来判断了。
参考博文: https://blog.csdn.net/wdhxs/article/details/109294536