什么是协商缓存和强缓存?两者有什么区别?
关于 HTTP 缓存
HTTP 缓存是基于 HTTP 协议的一种机制,通过存储和重用之前请求的资源副本(如 HTML、CSS、JavaScript、图片等),减少客户端与服务器之间的重复数据传输,从而提高网页加载速度、降低服务器负载、节省带宽。其核心目的是通过重用已有的响应数据,避免每次都从源服务器获取资源。
HTTP 缓存标准把缓存分为两类:
- 私有缓存: 私有缓存是绑定到特定客户端的缓存,通常指浏览器缓存。它存储的响应仅对当前用户可见,不与其他用户共享。适用场景:存储用户的个性化内容(如登录后的页面、用户特定数据)。
- 共享缓存:共享缓存位于客户端和服务器之间,存储的响应可被多个用户共享,用于减少服务器负载和网络流量。典型实现:代理服务器(如 Squid、Nginx 反向代理)、CDN 节点、ISP 缓存等。
关键性区别总结
特性 | 私有缓存 | 共享缓存 |
---|---|---|
存储位置 | 客户端 | 中间层(代理服务器、CDN、反向代理服务器) |
共享性 | 私有 | 共享 |
适用场景 | 个性化、登录后的页面、用户特定数据 | 公共资源、静态资源(图片、css) |
控制指令 | Cache-Control: private | Cache-Control: public |
安全性 | 仅对当前用户可见,安全 | 可被多个用户共享,不安全 |
HTTP 缓存控制指令
HTTP 缓存主要通过请求头和响应头中的字段(如 Cache-Control
、Expires
、Last-Modified
、ETag
等) 控制缓存策略,分为以下两种工作方式:
- 强缓存: 强缓存是指浏览器在第一次请求资源并得到响应后,将响应存储在客户端缓存中,后续再请求相同的资源时,浏览器会直接从缓存中获取响应,而不会向服务器发起请求。 由
Cache-Control
(HTTP 1.1) 或Expires
(HTTP 1.0) 指令控制,如Cache-Control: max-age=3600
,表示缓存 1 小时。 - 协商缓存:协商缓存是指客户端在请求资源时,会携带一些请求头信息,如
Last-Modified/If-Modified-Since
(使用资源最后修改时间判断)、ETag/If-None-Match
(使用资源唯一标识符判断) 等, 服务器根据这些请求头信息判断客户端是否需要更新资源,如果客户端不需要更新,则返回 304 Not Modified,否则返回 200 OK。
缓存破坏(解决前端部署后的缓存问题)
在现代 Web 开发中,JavaScript 和 CSS 资源会随着开发的进展而频繁更新。但由于其静态资源文件名未改变,浏览器会优先从缓存中获取,从而导致页面加载时出现旧版本的资源。为了解决这个问题,我们可以通过一些方法来破坏缓存:
- 使用基于版本号或哈希值的文件名: 在构建时,使用基于版本号或哈希值的文件名,如
main.js?v=1.0.0
,这样每次部署后文件名都会改变,从而破坏缓存。(一些成熟的构建工具如 Webpack、Vite 等,都提供了内置的版本号或哈希值生成功能) - 对于主资源禁用缓存: 与子资源不同,主资源的 URL 不能像子资源 URL 一样被修饰,这时我们可以在 html 的 head 标签中添加以下内容,防止其被浏览器缓存。
html
<meta
http-equiv="Cache-Control"
content="no-cache, no-store, must-revalidate"
/>
<meta
http-equiv="Pragma"
content="no-cache"
/>
<meta
http-equiv="Expires"
content="0"
/>
注意: 现代浏览器可能忽略 Meta 标签,因此必须结合 HTTP 头使用。
Nginx
location / {
add_header Cache-Control "no-store, no-cache, must-revalidate";
add_header Pragma "no-cache";
expires 0;
}
如果优化 SPA 应用的首屏渲染速度?
首屏加载时间: 指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容