HTTP缓存

本文详细解析了HTTP缓存控制的多种指令,包括Expires、Cache-Control和Pragma的区别,以及缓存校验的ETag和Last-Modified机制。重点介绍了强缓存和协商缓存的工作原理,以及如何通过Cache-Control设置缓存策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Http缓存

  • 缓存控制:控制缓存的开关,用于标识请求或访问中是否开启了缓存,使用了哪种缓存方式。

  • 缓存校验:如果缓存控制开关打开,如何校验缓存,比如怎么定义缓存的有效期,怎么确保缓存是最新的。

缓存控制

1. Expires

2. Cache-Control

3. Pragma

Expires

Expires 响应头包含日期/时间, 即在此时候之后,响应过期。

Expires因为是对时间设定的,且时间是Greenwich Mean Time (GMT),而不是本地时间,所以对时间要求较高。

Response Header
Expires: Wed, 21 Oct 2020 17:28:00 GMT

Cache-control

Cache-Control 通用消息头字段,被用于在http请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。

指令不区分大小写,并且具有可选参数,可以用令牌或者带引号的字符串语法。多个指令以逗号分隔。

缓存请求指令

客户端可以在HTTP请求中使用的标准 Cache-Control 指令。

Request Header
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached

缓存响应指令

服务器可以在响应中使用的标准 Cache-Control 指令。

Response Header
Cache-Control: must-revalidate
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: public
Cache-Control: private
Cache-Control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-Control: s-maxage=<seconds>

Cache-control的值可以按以下性质分类

1.可缓存性、控制开关

  • 否可以缓存,以及是私有还是共享缓存
public

表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容。(例如:1.该响应没有max-age指令或Expires消息头;2. 该响应对应的请求方法是 POST 。)

private

表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。私有缓存可以缓存响应内容,比如:对应用户的本地浏览器。

no-cache

在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证(协商缓存验证)。

no-store

缓存不应存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。

2. 缓存到期

max-age=

设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。

s-maxage=

覆盖max-age或者Expires头,但是仅适用于共享缓存(比如各个代理),私有缓存会忽略它。

max-stale[=]

表明客户端愿意接收一个已经过期的资源。可以设置一个可选的秒数,表示响应不能已经过时超过该给定的时间。

min-fresh=

表示客户端希望获取一个能在指定的秒数内保持其最新状态的响应。

3.重新验证和重新加载

must-revalidate

一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。

proxy-revalidate

与must-revalidate作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。

4.其他

no-transform

不得对资源进行转换或转变。Content-Encoding、Content-Range、Content-Type等HTTP头不能由代理修改。例如,非透明代理或者如Google’s Light Mode可能对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。no-transform指令不允许这样做。

only-if-cached

表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝。

Cache-Control缓存策略

HTTP/1.1定义的 Cache-Control 头用来区分对缓存机制的支持情况, 请求头和响应头都支持这个属性。通过它提供的不同的值来定义缓存策略。

1.没有缓存

缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。

Request Header
Cache-Control: no-store

表示客户端不希望这个请求的响应进行任何缓存

Response Header
Cache-Control: no-store

表示服务端不希望对个资源进行任何缓存

2.缓存但重新验证

如下头部定义,此方式下,每次有请求发出时,缓存会将此请求发到服务器,服务器端会验证请求中所描述的缓存是否过期,若未过期(注:实际就是返回304),则缓存才使用本地缓存副本。

Request Header
Cache-Control: no-cache

表示客户端希望用协商缓存的方式进行缓存

Response Header
Cache-Control: no-cache

表示服务端希望用协商缓存的方式进行缓存

3.私有和公共缓存

“public” 指令表示该响应可以被任何中间人(比如中间代理、CDN等)缓存。若指定了"public",则一些通常不被中间人缓存的页面(因为默认是private)(比如 带有HTTP验证信息(帐号密码)的页面 或 某些特定状态码的页面),将会被其缓存。

“private” 则表示该响应是专用于某单个用户的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。

Response Header
Cache-Control: private
or
Cache-Control: public

可以结合协商缓存

Cache-Control: public,no-cache
Cache-Control: private,no-cache

4.强缓存

过期机制中,最重要的指令是 “max-age=”,表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改变的文件,通常可以手动设置一定的时长以保证缓存有效,例如图片、css、js等静态资源。

Request Header
Cache-Control: max-age=31536000

配合Age请求头 来表示客户端缓存资源是否到期

Cache-Control: max-age=31536000
Age: 10
Response Header
Cache-Control: max-age=31536000

可以结合私有和公共缓存

私有强缓存

Cache-Control: private,max-age=31536000

公共强缓存

Cache-Control: public,max-age=31536000

表示服务端当前资源如果做缓存后可用的时间
5.验证方式

当使用了 “must-revalidate” 指令,那就意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。

Response Header
Cache-Control: must-revalidate

表示服务端希望客户端进行验证

Cache-control --VS-- Expires

Cache-control内容要远比Expires复杂的多,也是本文重点。

  1. ExpiresHTTP1.0协议中用来控制缓存的http头,Cache-ControlHTTP1.1协议新版的API。现在首选 Cache-Control。如果在Cache-Control响应头设置了 “max-age” 或者 “s-max-age” 指令,那么 Expires 响应头会被忽略。

  2. HTTP1.1协议中的,因为有了Cache-control,所以可以忽略上面提到的Expires。因为Cache-Control相对于Expires更加具体,细致。
    且,就算同时设置了Cache-ControlExpiresCache-Control的优先级也高于Expires

Pragma

Pragma 是一个在 HTTP/1.0 中规定的通用首部,这个首部的效果依赖于不同的实现,所以在“请求-响应”链中可能会有不同的效果。它用来向后兼容只支持 HTTP/1.0 协议的缓存服务器,那时候 HTTP/1.1 协议中的 Cache-Control 还没有出来。

Cache-Control: no-cache
Pragma: no-cache 

**注意:**由于 Pragma 在 HTTP 响应中的行为没有确切规范,所以不能可靠替代 HTTP/1.1 中通用首部 Cache-Control,尽管在请求中,假如 Cache-Control 不存在的话,它的行为与 Cache-Control: no-cache 一致。建议只在需要兼容 HTTP/1.0 客户端的场合下应用 Pragma 首部。

缓存的两种形式

  • 强缓存:浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-control和expires信息),若命中直接从缓存中获取资源信息,包括缓存header信息;本次请求根本就不会与服务器进行通讯

  • 协商缓存:若是没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/If-Modified-Since和Etag/If-None-Match),由服务器根据请求中的相关header信息来比对结果是否协商缓存命中;若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,可是并不返回资源内容,它会告知浏览器能够直接从缓存获取;不然返回最新的资源内容

缓存校验

当缓存控制采用

Cache-Control: no-cache
Cache-Control: max-age=0
Cache-Control: must-revalidate

以上等情况时表示,表示使用协商缓存的方式
响应头ETag —对应— 请求头If-None-Match

响应头Last-Modified —对应— 请求头If-Modified-Since

ETag

作为缓存的一种强校验器,ETag 响应头是一个对用户代理(User Agent, 下面简称UA)不透明的值。对于像浏览器这样的HTTP UA,不知道ETag代表什么,不能预测它的值是多少。如果资源请求的响应头里含有ETag, 客户端可以在后续的请求的头中带上 If-None-Match 头来验证缓存。

Reqsponse Header
ETag: "3e86-410-3596fbbc"

If-None-Match

If-None-Match 是一个条件式请求首部。对于 GET 和 HEAD 请求方法来说,当且仅当服务器上没有任何资源的ETag属性值与这个首部中列出的相匹配的时候,服务器端会才返回所请求的资源,响应码为200。对于其他方法来说,当且仅当最终确认没有已存在的资源的ETag属性值与这个首部中所列出的相匹配的时候,才会对请求进行相应的处理。

Request Header
If-None-Match: "3e86-410-3596fbbc"

一般ETag的值是资源的MD5值,由服务端开发人员在响应头中返回,当客户端再次发起相同的请求时,请求头中添加If-None-Match

If-None-Match: "3e86-410-3596fbbc"

服务端人员可以通过下面的伪代码来判断如何进行返回

if(request.header("If-None-Match") == "3e86-410-3596fbbc") 
{
    response.statuscode = 304;
}
else
{
    response.write(string);
}

If-None-Match:告诉服务器如果一致,返回状态码304,不一致则返回资源。

Last-Modified

Last-Modified响应头可以作为一种弱校验器。说它弱是因为它只能精确到一秒。如果响应头里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存。

Reponse Header

Last-Modified 文件最后修改时间 秒级别

Last-Modified: Thu, 03 Jul 2018 00:00:00 GMT

If-Modified-Since

If-Modified-Since 是一个条件式请求首部,服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 。如果请求的资源从那时起未经修改,那么返回一个不带有消息主体的 304 响应,而在 Last-Modified 首部中会带有上次修改时间。 不同于 If-Unmodified-Since, If-Modified-Since 只可以用在 GET 或 HEAD 请求中。

当与 If-None-Match 一同出现时,它(If-Modified-Since)会被忽略掉,除非服务器不支持 If-None-Match。

Request Header
If-Modified-Since: Thu, 03 Jul 2018 00:00:00 GMT

如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。

如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。

从这个GMT指定时间开始 未修改过

请求网站的时间

Date: Tue, 11 Jul 2000 18:23:51GMT

参考文献

HTTP Headers

HTTP 缓存

http协商缓存VS强缓存

HTTP缓存讲义

<think>好的,用户现在想了解HTTP缓存的工作原理以及前端CDN的缓存解决方案。之前我提供了关于前端CDN缓存的详细内容,现在需要结合用户的新问题,整合HTTP缓存机制,并参考用户提供的引用内容。 首先,我需要回顾HTTP缓存的基本概念,包括强制缓存和协商缓存。用户提供的引用[1]中提到,使用Cache-Control头来控制缓存,比如no-store、no-cache等,还提到Nginx配置禁用HTML缓存的方法。这可能涉及到不同资源类型的缓存策略,比如HTML文件通常不缓存或使用协商缓存,而静态资源如图片、JS、CSS可以长期缓存。 接着,用户提到CDN缓存解决方案,之前回答中已经涉及了CDN的缓存流程、优化策略、多CDN加速等。需要将HTTP缓存与CDN缓存结合起来,解释它们如何协同工作。例如,CDN边缘节点会遵循源站的缓存头设置,如Cache-Control和Expires,同时CDN自身也有缓存策略,比如回源条件和缓存失效机制。 用户引用的内容还提到了缓存命中率的问题,引用[1]指出Private可能影响CDN缓存命中率,但量不大时可以禁用。这可能涉及到缓存头的正确配置,避免不必要的私有缓存导致CDN无法有效缓存资源。需要解释不同Cache-Control指令对CDN的影响,比如public、private、no-cache等。 另外,用户引用中的Nginx配置示例展示了如何为HTML文件设置不缓存,这需要在前端部署时注意,确保入口文件如HTML使用协商缓存或强制不缓存,而带版本号的静态资源使用长期缓存。结合之前回答中的版本控制技巧,比如Webpack生成带哈希的文件名,可以确保资源更新后URL变化,从而绕过缓存。 用户可能还想了解如何解决常见的HTTP缓存问题,比如缓存更新不及时,或者缓存策略配置错误导致的问题。例如,使用版本化文件名来避免缓存问题,或者在需要立即更新时通过CDN刷新或修改URL。引用[1]中提到的解决方案是通过修改URL触发缓存失效,这与之前回答中的建议一致。 还需要考虑CDN如何加速动态内容,引用[2]提到CDN的动态内容回源,可能需要结合边缘计算或动态压缩技术。之前的回答中提到了动态压缩的公式,可以再次强调这些优化手段。 最后,用户的问题可能涉及实际应用中的最佳实践,比如如何配置HTTP头和CDN策略,监控缓存命中率,处理安全性和性能的平衡。需要整合引用中的信息,如HTTPS强制、防盗链设置,以及监控指标如缓存命中率、TTFB等,确保回答全面且实用。 总结来说,需要将HTTP缓存机制与CDN缓存方案结合起来,详细解释两者的工作原理、配置策略、常见问题及解决方案,并参考用户提供的引用内容,确保回答准确且符合用户的实际需求。</think>### HTTP 缓存机制与前端 CDN 缓存解决方案 --- #### 一、HTTP 缓存核心原理 HTTP 缓存通过**客户端与服务器的协作**实现资源复用,主要分为两类: 1. **强制缓存** - 通过 `Cache-Control` 或 `Expires` 头直接判断缓存是否有效 - **典型配置**: ```http Cache-Control: public, max-age=86400 // 缓存1天 ``` - **触发条件**: - 时间未超过 `max-age` - 资源未发生版本变更(如文件名哈希未变化) 2. **协商缓存** - 通过校验文件指纹(`ETag`/`Last-Modified`)确认资源是否更新 - **典型流程**: ```mermaid graph LR A[客户端请求] --> B{本地缓存} B -->|过期| C[携带If-None-Match/If-Modified-Since请求头] C --> D{服务器校验} D -->|未修改| E[返回304状态码] D -->|已修改| F[返回新资源+新缓存头] ``` 3. **关键头字段对比** | **指令** | 作用场景 | 对 CDN 的影响 | |-------------------|----------------------------|----------------------------------------| | `public` | 允许所有节点缓存 | CDN 边缘节点可缓存资源 | | `private` | 仅允许浏览器缓存 | CDN 无法缓存,显著降低命中率[^1] | | `no-cache` | 需向服务器验证 | CDN 回源校验,增加延迟但保证内容新鲜度 | | `no-store` | 完全禁用缓存 | CDN 和浏览器均不缓存 | --- #### 二、CDN 缓存HTTP 缓存的协同 CDN 本质是**分布式 HTTP 缓存代理**,其行为依赖源站配置: 1. **缓存继承规则** - CDN 节点默认遵循源站的 `Cache-Control` 和 `Expires` 头 - **示例冲突处理**: - 若源站设置 `Cache-Control: private`,CDN 将拒绝缓存 - 若源站设置 `Cache-Control: public, max-age=3600`,CDN 缓存1小时 2. **缓存分层架构** ```mermaid graph TD A[用户] --> B[CDN边缘节点] B -->|缓存命中| C[直接返回] B -->|缓存未命中| D[CDN父节点] D -->|缓存未命中| E[源服务器] E --> D[回源并缓存] D --> B[逐层下发] ``` 3. **前端最佳实践** - **入口文件(HTML)** ```nginx # Nginx 配置示例:禁止缓存 HTML[^1] location ~* \.(html|htm)$ { add_header Cache-Control "no-cache, must-revalidate"; } ``` - **版本化静态资源(JS/CSS)** ```html <!-- Webpack 生成的带哈希文件名 --> <script src="https://cdn.com/app.3a7b2c8d.js"></script> ``` ```http Cache-Control: public, max-age=31536000 # 1年长期缓存 ``` --- #### 三、常见问题解决方案 1. **缓存更新失效** - **场景**:修改了 JS 文件但用户仍访问旧版本 - **根因**:未更新 URL 或缓存头配置错误 - **修复方案**: - 文件名添加内容哈希(如 `main.[contenthash:8].js`) - 主动刷新 CDN 缓存(需调用 CDN API) 2. **CDN 命中率低** - **排查步骤**: 1. 检查源站 `Cache-Control` 是否包含 `private` 或 `no-store`[^1] 2. 确认 CDN 配置未覆盖源站缓存头 3. 分析用户请求是否过于分散(如大量随机 URL 参数) 3. **动态 API 加速** - **CDN 边缘计算方案**: - 缓存高频查询结果(如商品详情页) - 使用 `Cache-Control: s-maxage=60` 控制 CDN 缓存时间 $$ T_{响应} = \frac{命中次数}{总请求次数} \times T_{CDN} + \frac{未命中次数}{总请求次数} \times (T_{CDN} + T_{回源}) $$ --- #### 四、进阶优化策略 1. **分级缓存策略** | **资源类型** | 浏览器缓存 | CDN 缓存 | 实现方式 | |-------------------|------------------|------------------|----------------------------------| | 入口 HTML | `no-cache` | 不缓存 | Nginx 规则匹配[^1] | | 版本化 JS/CSS | 1年 | 1年 | Webpack 哈希输出 + CDN 继承头 | | 用户个性化内容 | `private, 60s` | 不缓存 | Vary: Cookie 头 | 2. **缓存监控体系** - **核心指标**: - 浏览器缓存利用率(通过 `PerformanceResourceTiming` API 采集) - CDN 命中率(需从 CDN 服务商获取日志) - **告警阈值**: - CDN 命中率 < 85% → 触发优化任务 - HTML 文件缓存率 > 5% → 检查配置错误 --- #### 五、实践案例 **某新闻网站优化前后对比** | **问题** | 优化前现象 | 优化方案 | 结果 | |-------------------------|------------------------------|----------------------------------|------------------------------| | 首页加载慢 | JS/CSS 未缓存,重复下载 | 添加文件哈希 + 长期缓存头 | 资源加载时间减少 68% | | CDN 费用过高 | 图片请求回源率 45% | 调整 `Cache-Control: max-age=604800` | 回源率降至 12%,月节省 \$8k | | 用户看到旧页面 | HTML 被 CDN 缓存 | 强制 `no-cache` + 版本化部署 | 页面更新延迟从 2h 缩短至 10s | --- ### 相关问题 1. 如何通过 `Vary` 头实现个性化内容缓存? 2. `s-maxage` 与 `max-age` 在 CDN 场景下的区别? 3. 如何设计多环境(测试/生产)的 CDN 缓存策略? 4. Service Worker 如何与 HTTP 缓存协同工作?[^1] --- : 引用自站内资料:浏览器缓存机制及 Nginx 配置方案 [^2]: 引用自站内资料:CDN 加速流程与缓存分层架构
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值