网络方面的缓存分为三块:DNS缓存、HTTP缓存、CDN缓存,也有人把这里的 HTTP 缓存称为浏览器缓存。
还有本地的就是:浏览器的本地存储和离线存储,更快提高首屏加载速度,让页面飞起
# 1、DNS缓存
进入页面的时候会进行DNS查询,找到域名对应的服务器的IP地址,再发送请求
# 2、HTTP缓存
就是将http请求获取的页面资源存储在本地,之后再加载直接从缓存中获取而不用请求服务器,从而响应更快。先看图:
# 2-1、强缓存
- 强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程,强制缓存的情况主要有三种
1.不存在该缓存结果和缓存标识,强制缓存失效,则直接向服务器发起请求(跟第一次发起请求一致),如下图:
2.存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存(暂不分析),如下图
3.存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果,如下图
控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高。
# Expires:用来指定资源到期绝对时间,服务器响应时,添加在响应头中。
expires: Wed, 22 Nov 2021 08:41:00 GMT
注意:如果服务器和浏览器端时间不一致的话可能导致失败。
比如现在时间是8月1,expires过期时间是8月2,客户端把电脑时间改成了8月3,那就用不了这个缓存
# Cache-Control:指定资源过期时间秒,如下,表示在这个请求正确返回后的300秒内,资源可以使用,否则过期。添加在响应头中。
cache-control:max-age=300
Expires 和 Cache-Control 的区别
1、Expires 是HTTP/1.0中的,Cache-Control 是HTTP/1.1中的;
2、两者同时存在的话 Cache-Control 优先级高于 Expires;
强缓存的缺点:
就是缓存过期之后,不管资源有没有变化,都会重新发起请求,重新获取资源
而实际情况是在资源文件没有更新的情况下,即使过期了也不重新获取资源,继续使用旧资源,
所以协商缓存它来了,在强缓存过期的情况下,再走协商缓存的流程,判断文件有没有更新。
- Cache-Control 缓存能力指令
指令 | 说明 |
---|---|
public | 响应可以被任何缓存(浏览器、CDN、代理服务器等)缓存 |
private | 响应只能被单个用户的浏览器缓存,不允许共享缓存(如CDN)存储 |
no-store | 禁止缓存任何响应内容(最严格的限制) |
no-cache | 可以缓存但每次使用前必须向服务器验证(不是"不缓存"的意思) |
must-revalidate | 缓存必须在使用前验证过期资源,不可使用过期资源 |
- Cache-Control 缓存期限指令
指令 | 说明 |
---|---|
max-age=<seconds> | 资源被视为新鲜的最长时间(秒) |
immutable | 表示资源永不过期,减少验证请求(适用于带哈希的静态资源) |
- Cache-Control 指令组合示例
- 静态资源长期缓存,适用于带内容哈希的文件(如 style.a1b2c3d4.css)
Cache-Control: public, max-age=31536000, immutable
- 动态内容短时缓存,适用于个性化内容,每10分钟验证一次
Cache-Control: private, no-cache, max-age=600
- 敏感内容禁止缓存,适用于银行交易、登录页面等
Cache-Control: no-store
# 2-2、协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
1.协商缓存生效,返回304,如下
2.协商缓存失效,返回200和请求结果结果,如下
控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match
其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。
# 2-2-1、Last-Modified/If-Modified-Since
第一次请求资源时,服务器除了会返回给浏览器上面说的过期时间,还会在响应头添加 Last-Modified 字段,告诉浏览器该资源的最后修改时间
last-modified: Fri, 27 Oct 2021 08:35:57 GMT
然后浏览器再次请求的时候就把这个时间再通过另一个字段 If-Modified-Since 添加到请求头,发送给服务器
if-modified-since: Fri, 27 Oct 2021 08:35:57 GMT
服务器再把这两个字段的时间对比,如果是一样的,就说明文件没有被更新过,就返回状态码304和空响应体给浏览器,浏览器直接拿过期了的资源继续使用即可;如果对比不一样说明资源有更新,就返回状态码200和新的资源。
所以说 Last-Modified/If-Modified-Since 是成对的,是为了对比文件修改时间
Last-Modified/If-Modified-Since的缺点:
1、如果本地打开了缓存文件,即使没有对文件进行修改,但还是会造成Last-Modified被修改,服务器端不能命中缓存导致发送相同资源
2、因为Last-Modified只能以秒计时,如果在不可感知的时间内修改了文件,服务器端会认为还是命中了,无法返回正确的资源
3、如果资源有周期性变化,如资源修改后,在一个周期内又改回了原来的样子,我们认为这个周期前的缓存是可以使用的,但是Last-Modified不这样认为
# 2-2-2、ETag/If-None-Match
第一次请求资源时,服务器除了会在响应头上返回Expires、Cache-Control、Last-Modified,还在返回Etag字段,表示当前资源文件的一个唯一标识。
这个标识符由服务器基于文件内容编码生成,能精准感知文件的变化,只要文件内容不同,ETag就会重新生成
etag: W/"132489-1627839023000"
然后浏览器再次请求的时候就把这个文件标识 再通过另一个字段 If-None-Match,发送给服务器
if-none-match: W/"132489-1627839023000"
服务器再把这两个字段对比,如果发现是一样的,就说明文件没有被更新过,就返回状态码304和空响应体给浏览器,浏览器直接拿过期了的资源继续使用;
如果对比不一样说明资源有更新,就返回状态码200和新的资源。
- ETag 的生成方式
- 基于内容哈希(最常用)
- 基于文件系统属性
- 基于数据库字段
- 基于时间戳(简单实现)
Last-Modified 和 ETag 的区别:
1、Etag 感知文件精准度要高于 Last-Modified
2、同时使用时,服务器校验优先级 Etag/If-None-Match
3、Last-Modified 性能上要优于 Etag,因为 Etag 生成过程中需要服务器付出额外开销,会影响服务器端的性能,所以它并不能完全替代 Last-Modified,只能作为补充和强化
Nginx 默认ETag生成
Nginx 使用最后修改时间+内容长度的十六进制组合:
ETag: "5d8c72a5-264" # 格式:修改时间-内容长度
# 强缓存与协商缓存的区别:
- 优先查找强缓存,没有命中再查找协商缓存
- 强缓存不发请求到服务器,所以有时候资源更新了浏览器还不知道,但是协商缓存会发请求到服务器,资源是否有更新,服务器肯定知道
- 目前项目大多数使用缓存的方案
1、协商缓存一般存储:HTML
2、强缓存一般存储:css, image, js,文件名带上 hash
# 3、本地缓存
# cookies,sessionStorage 和 localStorage
共同点:都是保存在浏览器端,且同源的
特性 | Cookies | sessionStorage | localStorage |
---|---|---|---|
存储容量 | 每个域名约 50-150 个, 4KB 左右 | 5-10MB(不同浏览器不同) | 5-10MB(甚至更大) |
生命周期 | 可设置过期时间(默认会话级,关闭浏览器后清除) 通过 expires 或 max-age 设置过期时间 | 会话级(关闭标签页清除) | 永久存储(需手动清除) |
作用域 | 同域名下所有标签页共享 | 仅当前标签页 | 同域名下所有标签页共享 |
同步行为 | 修改后立即同步 | 完全不共享 | 需通过 storage 事件监听同步 |
是否随请求发送 | 是(自动附加到 HTTP 请求头) | 否 | 否 |
典型用途 | 用户认证、会话跟踪 | 临时表单数据、页面间传参 | 长期存储(如用户偏好设置) |
删除单个数据 | 设置过期时间为过去或 Max-Age=0 | removeItem(key) | removeItem(key) |
清空所有数据 | 遍历所有Cookie逐个删除 | clear() | clear() |
自动失效机制 | 依赖 Expires/Max-Age 设置 | 标签页关闭自动清除 | 无,需手动或程序控制 |
安全注意事项 | 敏感数据应标记 HttpOnly 和 Secure(防止 XSS 和嗅探) | 不要存储敏感信息(如密码),易受 XSS 攻击 | 不要存储敏感信息(如密码),易受 XSS 攻击 |