📌面试答不上的问题-HTTP缓存

📌 面试答不上的问题

📌 HTTP缓存

🔹 HTTP 缓存是什么?

HTTP 缓存通过在客户端(如浏览器)存储已获取的资源副本,减少重复请求,提高访问速度,优化用户体验,并降低服务器负载。即使在离线状态,已缓存的资源仍可访问。

🔹 缓存适用范围

  • 静态资源(适合缓存):HTML、CSS、JS、图片、字体等。
  • 动态资源(一般不缓存):如购物车、用户数据、订单信息,因数据实时变化,缓存可能导致信息不一致。

🔹 如何优化缓存?

  1. 强缓存Cache-Control / Expires):优先使用本地缓存,减少请求。
  2. 协商缓存ETag / Last-Modified):资源更新时才重新下载,避免使用过期数据。
  3. 动态资源优化 :可采用短时缓存 + 协商缓存,兼顾性能与数据实时性。

合理配置 HTTP 缓存,可提升性能并避免过时数据影响用户体验! 🚀

🔹 HTTP缓存的分类

HTTP 缓存主要分为两种:强缓存和协商缓存

强缓存

强缓存 (Strong Cache)通过在 HTTP 响应头中设置**Cache-Control** 和 Expires ,让浏览器在缓存有效期内直接使用本地缓存,而不向服务器发送请求,从而提高加载速度和减少服务器压力。

🔹 强缓存的实现方式
1. Cache-Control(优先级高,HTTP/1.1)

Cache-Control现代浏览器主要使用的缓存控制字段,支持更精细的缓存管理。

📌 关键指令-配置请求头
指令 作用
max-age=3600 设置缓存有效时间(秒),这里是 1 小时
no-cache 每次请求都要向服务器确认是否有新版本(走协商缓存
no-store 不缓存,每次都从服务器获取
public 允许任何人(包括 CDN)缓存
private 只能被客户端缓存,CDN 不能缓存
immutable 资源不会更改,即使 F5 也不会重新请求
2. Expires(HTTP/1.0,已被 Cache-Control 取代)

Expires 指定资源的过期时间(绝对时间) ,浏览器在过期时间前直接使用缓存。

❌ 问题
  • 依赖客户端时间,如果用户本地时间不准确,可能导致缓存异常。
  • Cache-Control 覆盖,现代浏览器一般不使用它。
✅ 示例
http 复制代码
Expires: Wed, 21 Oct 2025 07:28:00 GMT

含义 :资源在 2025 年 10 月 21 日 07:28:00 之前有效。
🚀 推荐优先使用 Cache-Control,因为它更灵活和可靠!


🔹 强缓存的特点

不会向服务器发送请求 ,直接从本地缓存读取,加载速度极快

适用于静态资源 (如 CSS、JS、图片、字体等)。

不能及时更新,如果资源变更但仍在缓存期内,客户端不会请求最新版本。


🔹 如何解决强缓存更新问题?

如果资源内容变更了,但缓存仍然有效,用户可能看不到最新版本。常见的解决方案:

1. 文件名加 Hash

在文件名中添加 hash,确保文件变更时 URL 也变:

复制代码
app.js  →  app.123abc.js

优点 : ✅ 旧缓存不会影响新文件

✅ 适用于前端构建工具(如 Webpack)


2. 版本号参数

在 URL 后加 ?v=20250312

arduino 复制代码
https://example.com/app.js?v=20250312

优点 : ✅ 服务器可以控制更新策略

❌ 可能会被部分 CDN 忽略


🔹 什么时候用强缓存?
资源类型 适用缓存策略
CSS / JS Cache-Control: max-age=31536000, immutable,并加 hash
图片 / 字体 Cache-Control: max-age=31536000, public,并加 hash
API 数据 不使用强缓存 ,改用协商缓存(ETag / Last-Modified

🔹 总结
  1. Cache-Control: max-age=xxx 是最常用的强缓存方式,Expires 更可靠
  2. 强缓存不会请求服务器,适用于静态资源。
  3. 避免缓存问题 ,建议使用 hash 或版本号来控制文件更新。

协商缓存

协商缓存(also known as Conditional Caching)是 HTTP 缓存的一种机制,能够有效提升网页的加载速度,减少服务器压力。它的核心是通过使用请求和响应中的特定头部信息来确保资源的有效性,从而避免不必要的资源下载。

在协商缓存中,常见的头部有:

Last-Modified / If-Modified-Since

Last-ModifiedIf-Modified-Since 是 HTTP 协商缓存机制中非常关键的两个头部字段,它们用来协商是否需要重新从服务器获取资源,避免不必要的重复下载。

  1. 第一次请求 :客户端请求资源,服务器返回资源并带有 Last-Modified 字段。

  2. 第二次请求 :客户端带上 If-Modified-Since 头部,服务器根据该时间检查资源是否修改。

    • 如果资源没有变化,服务器返回 304 Not Modified,客户端继续使用缓存。
    • 如果资源有变化,服务器返回新的资源和 Last-Modified 时间,客户端更新缓存。
注意事项
  • 精度限制Last-Modified 的精度通常只有到秒,而有些服务器的文件系统可能支持毫秒级的修改时间。这样可能会导致某些情况下无法准确判断资源是否修改。
  • 效率问题 :对于频繁更新的资源(比如动态生成的内容),Last-ModifiedIf-Modified-Since 的机制可能不太适用,可能需要其他方式来管理缓存(比如 ETag)。
ETag / If-None-Match

ETagIf-None-Match 是另一种常用的 HTTP 协商缓存机制,它们相比 Last-Modified / If-Modified-Since 更为精确,因为它们可以通过一个独特的标识符来判断资源是否发生了变化。

  1. 第一次请求 :客户端请求资源,服务器返回资源并带上 ETag 字段。

  2. 第二次请求 :客户端带上 If-None-Match 头部,服务器根据该 ETag 值检查资源是否修改。

    • 如果资源没有变化,服务器返回 304 Not Modified,客户端继续使用缓存。
    • 如果资源有变化,服务器返回新的资源和 ETag,客户端更新缓存。
优点与 Last-Modified 的对比
  • 精确度更高ETag 可以比 Last-Modified 更精确地标识资源的变化,因为它是一个自定义的标识符,通常可以精确到文件的每一个微小变化。
  • 无时间依赖ETag 不依赖于时间戳,因此它可以避免 Last-Modified 精度不够的情况,尤其是当文件的修改时间没有变化但内容发生变化时,ETag 可以有效地判断出资源是否变化。

🔹 静态资源缓存策略

资源类型 是否缓存 推荐缓存策略
HTML ✅ 可以缓存(但建议短时缓存) Cache-Control: no-cache, must-revalidate,避免加载过期页面
CSS/JS ✅ 建议缓存 Cache-Control: max-age=31536000, immutable 并使用文件 hash 版本号
图片、字体 ✅ 强烈建议缓存 Cache-Control: max-age=31536000 并使用 CDN
API 数据 ❌ 不建议缓存 Cache-Control: no-store 确保数据实时性

🔹 缓存策略-前端实现方式

在前端代码中,可以使用 JavaScript 来检查和控制 HTTP 缓存行为,主要涉及 Cache-Control、Expires、Last-Modified / If-Modified-Since、ETag / If-None-Match 这些 HTTP 头部。

在前端代码中的使用方式:

1. Cache-Control & Expires

Cache-ControlExpires 主要用于强缓存(不需要请求服务器,直接使用本地缓存)。

方式 1:通过 <meta> 标签控制缓存
html 复制代码
<meta http-equiv="Cache-Control" content="max-age=3600, must-revalidate">
<meta http-equiv="Expires" content="Wed, 21 Oct 2025 07:28:00 GMT">
  • max-age=3600:设置缓存有效期为 3600 秒(1 小时)。
  • must-revalidate:缓存过期后必须重新向服务器验证资源。
  • Expires:指定资源过期时间(但 Cache-Controlmax-age 优先级更高)。
方式 2:前端发起请求时手动设置 Cache-Control

fetchXMLHttpRequest 请求中可以手动控制 Cache-Control

javascript 复制代码
fetch('/api/data', {
  method: 'GET',
  headers: {
    'Cache-Control': 'no-cache', // 禁用强缓存,每次都重新请求
  }
})
  .then(response => response.json())
  .then(data => console.log(data));

常见的 Cache-Control 值:

  • no-cache:每次请求都向服务器验证资源是否更新(走协商缓存)。
  • no-store:完全不缓存,每次都重新下载资源。
  • max-age=3600:缓存 1 小时。
  • private:只能被浏览器缓存,代理服务器不能缓存。
  • public:浏览器和代理服务器都可以缓存。

2. Last-Modified / If-Modified-Since

Last-ModifiedIf-Modified-Since 用于协商缓存,前端可以通过 fetchXMLHttpRequest 查看它们。

方式 1:检查 Last-Modified

前端可以发送请求,并查看服务器返回的 Last-Modified

javascript 复制代码
fetch('/api/data', {
  method: 'GET'
})
  .then(response => {
    console.log('Last-Modified:', response.headers.get('Last-Modified'));
    return response.json();
  })
  .then(data => console.log(data));
方式 2:发送 If-Modified-Since

客户端手动带上 If-Modified-Since 头部,询问服务器资源是否更新:

javascript 复制代码
fetch('/api/data', {
  method: 'GET',
  headers: {
    'If-Modified-Since': 'Wed, 10 Mar 2025 10:00:00 GMT'
  }
})
  .then(response => {
    if (response.status === 304) {
      console.log('资源未更新,使用缓存');
    } else {
      return response.json();
    }
  })
  .then(data => console.log(data));
  • 如果资源未修改 ,服务器返回 304 Not Modified,浏览器使用本地缓存数据。
  • 如果资源已修改 ,服务器返回 200 OK 并带回最新的资源。

3. ETag / If-None-Match

ETag 是比 Last-Modified 更精确的缓存校验方式,前端可以查看 ETag,并在下次请求时带上 If-None-Match

方式 1:获取 ETag
javascript 复制代码
fetch('/api/data')
  .then(response => {
    console.log('ETag:', response.headers.get('ETag'));
    return response.json();
  })
  .then(data => console.log(data));
方式 2:发送 If-None-Match
javascript 复制代码
fetch('/api/data', {
  method: 'GET',
  headers: {
    'If-None-Match': '"abc123"'
  }
})
  .then(response => {
    if (response.status === 304) {
      console.log('资源未更新,使用缓存');
    } else {
      return response.json();
    }
  })
  .then(data => console.log(data));
  • 如果 ETag 匹配 ,服务器返回 304 Not Modified,前端使用缓存数据。
  • 如果 ETag 不匹配 ,服务器返回 200 OK,并带回最新资源。

4. 结合 Cache-ControlETagLast-Modified

如果要完整控制缓存,可以结合 Cache-ControlETagLast-Modified

javascript 复制代码
fetch('/api/data', {
  method: 'GET',
  headers: {
    'Cache-Control': 'no-cache', // 先检查服务器是否有更新
    'If-None-Match': '"abc123"', // 带上上次缓存的 ETag
    'If-Modified-Since': 'Wed, 10 Mar 2025 10:00:00 GMT' // 带上上次的 Last-Modified
  }
})
  .then(response => {
    if (response.status === 304) {
      console.log('资源未修改,使用缓存');
    } else {
      console.log('资源已更新,获取新数据');
      return response.json();
    }
  })
  .then(data => console.log(data));

总结
机制 类型 控制方式 适用场景
Cache-Control 强缓存 fetch 头部或 <meta> 控制缓存时间、是否使用缓存
Expires 强缓存 <meta> 或 HTTP 头部 指定资源过期时间
Last-Modified / If-Modified-Since 协商缓存 fetch 请求头 资源基于修改时间更新
ETag / If-None-Match 协商缓存 fetch 请求头 资源基于唯一标识符更新

前端代码 中,可以通过 fetch 设置 Cache-ControlIf-None-MatchIf-Modified-Since 来控制 HTTP 缓存机制,合理利用缓存可以有效提升性能,减少带宽消耗! 🚀

相关推荐
前端之虎陈随易4 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·vue.js·人工智能·typescript·node.js
一路向北he4 小时前
字节钢铁军团--“提供情境,而非控制”
java·开发语言·前端
kyriewen4 小时前
豆包和千问同时关了智能体,我用它们搭的 3 个自动化全废了——迁移方案整理
前端·javascript·ai编程
前端一小卒4 小时前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
Waay4 小时前
面试口述版:个人对 Prometheus 完整理解
运维·学习·云原生·面试·职场和发展·kubernetes·prometheus
大圣编程6 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang6 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆7 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜7 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞8 小时前
异步HttpModule的实现方式
java·服务器·前端