图片缓存:浏览器刷新 和 304 Not Modified 与 If-Modified-Since 及 Cache-Control

本文详细解释了HTTP状态码304 Not Modified的工作原理及其应用场景,尤其是在客户端缓存利用方面的作用,并探讨了如何在服务器端实现该功能。

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

今天在用chrome浏览淘宝页面的时候,发现很多来自淘宝图片HTTP状态码是 304 Not Modified

到百度搜索了一下,明白了 304状态的含义(以下绿色内容来自网络):

304 Not Modified:客户端有缓冲的文件并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。

如果客户端在请求一个文件的时候,发现自己缓存的文件有 Last Modified ,那么在请求中会包含 If Modified Since ,这个时间就是缓存文件的 Last Modified 。因此,如果请求中包含 If Modified Since,就说明已经有缓存在客户端。只要判断这个时间和当前请求的文件的修改时间就可以确定是返回 304 还是 200 。对于静态文件,例如:CSS、图片,服务器会自动完成 Last Modified 和 If Modified Since 的比较,完成缓存或者更新。但是对于动态页面,就是动态产生的页面,往往没有包含 Last Modified 信息,这样浏览器、网关等都不会做缓存,也就是在每次请求的时候都完成一个 200 的请求。

我突然想起我所写的图片服务器没有实现HTTP 304 缓存功能。

这个 304 状态一般主要在用户刷新页面(F5键)的时候触发.
[b]当用户在刷新页面的时候,因为原来的页面里的很多图片已经缓存过,客户端的浏览器已经记录了图片的最后更新时间(Last Mod),所以在用户刷新页面的时候,会向服务器提交一个字段:If-Modified-Since: Wed, 08 Sep 2010 21:35:06 GMT
[/b]

这个时候,服务器端的程序先取得这个字段的值,然后与服务器上的图片最后修改时间对比,如果相同,就直接返回 304 Not Modified ,然后停止。这样就不用把图片重新传输到客户端,达到节省带宽的目的。

关于 Cache-Control: max-age=秒 和 Expires

Expires = 时间,HTTP 1.0 版本,缓存的载止时间,允许客户端在这个时间之前不去检查(发请求)
max-age = 秒,HTTP 1.1版本,资源在本地缓存多少秒。
如果max-age和同时存在,则被Cache-Control的max-age覆盖。

Expires 的一个缺点就是,返回的到期时间是服务器端的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大,那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代。

今天我还发现一个小的问题,是关于客户端的日期格式:

Wed, 08 Sep 2010 21:35:06 GMT 与 Wed, 8 Sep 2010 21:35:06 GMT

注意上面的格式,一个是8的前面有个前置的0,一个没有。

我发现firefox和chrome对这个日期格式处理一致,ie有点不同。
最终我修改了服务器端的程序:
//HTTP 日期格式: Wed, 08 Sep 2010 21:35:06 GMT
DateFormat dateFormatGMT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH); //时间格式
<think>我们被要求详细解释HTTP头字段If-Modified-SinceIf-None-Match的用途、工作方式以及它们在缓存控制条件请求中的应用场景。 根据用户提供的引用之前的问题,我们知道这两个头字段都属于条件请求头部,用于缓存验证(协商缓存)。 引用[1][2]说明了If-Modified-Since的作用:它基于资源最后修改时间(Last-Modified)进行缓存验证。 引用[3]则概括了整个HTTP缓存机制,包括强缓存(expirescache-control协商缓存(Etag/If-None-MatchLast-Modified/If-Modified-Since)。 下面我们将分别解释这两个头字段,并说明它们如何协同工作。 注意:在回答中,我们将使用中文,并按照要求对数学公式(如果有)使用LaTeX格式,但本题中数学公式较少,重点在解释机制。 另外,我们会在适当的地方引用用户提供的引用内容,并在末尾添加引用标识。 结构: 1. 介绍条件请求协商缓存的背景 2. 分别详细解释If-Modified-SinceIf-None-Match 3. 解释它们的工作流程(结合例子) 4. 讨论应用场景注意事项 5. 总结</think>### HTTP头字段`If-Modified-Since``If-None-Match`详解 #### 一、核心作用定位 这两个请求头字段均属于**条件请求(Conditional Requests)** 机制,用于实现**协商缓存(Validation Caching)**。其核心目标是在客户端已有缓存副本时,向服务器验证资源是否更新: - 若未更新 → 返回 `304 Not Modified` → 客户端直接使用缓存 - 若已更新 → 返回 `200 OK` 新资源 → 更新客户端缓存 ```mermaid graph LR A[客户端发起请求] --> B{携带缓存验证头} B -->|If-Modified-Since<br>或 If-None-Match| C[服务器] C -->|资源未修改| D[返回304] C -->|资源已修改| E[返回200+新资源] ``` #### 二、字段详细解析 ##### 1. `If-Modified-Since` - **作用原理**: 客户端携带**上次响应头中的`Last-Modified`时间值**(资源最后修改时间),服务器比较当前资源修改时间: - 若客户端时间 ≥ 服务器时间 → 返回 `304` - 若客户端时间 < 服务器时间 → 返回 `200` 新资源 - **工作流程**: 1. 首次请求:服务器返回资源及`Last-Modified: Fri, 31 Aug 2007 02:02:20 GMT` 2. 后续请求:客户端自动添加`If-Modified-Since: Fri, 31 Aug 2007 02:02:20 GMT` 3. 服务器校验时间戳决定响应状态[^1][^2] - **典型应用场景**: - 静态资源(如图片/CSS/JS文件)的缓存验证 - 修改频率较低的内容(如新闻文章) ##### 2. `If-None-Match` - **作用原理**: 客户端携带**上次响应头中的`ETag`值**(资源唯一标识符),服务器比较当前资源`ETag`: - 若`ETag`匹配 → 返回 `304` - 若`ETag`不匹配 → 返回 `200` 新资源 - **关键优势**: - 解决时间戳精度问题(如1秒内多次修改) - 处理特殊场景: - 资源内容不变但修改时间变化(如备份恢复) - 分布式服务器时间不同步 - 文件编码改变但内容不变(如gzip重压缩) - **工作流程**: 1. 首次请求:服务器返回`ETag: "45bae1-16a-46d776ac"` 2. 后续请求:客户端添加`If-None-Match: "45bae1-16a-46d776ac"` 3. 服务器校验`ETag`决定响应状态[^3] #### 三、协同工作优先级 1. **典型协作流程**: ```mermaid sequenceDiagram participant Client participant Server Client->>Server: GET /resource Server-->>Client: 200 OK + Last-Modified + ETag Client->>Server: GET /resource If-Modified-Since: [时间戳] If-None-Match: [ETag] alt 资源未修改 Server-->>Client: 304 Not Modified else 资源已修改 Server-->>Client: 200 OK + 新资源 end ``` 2. **优先级规则**: - 当两者同时存在时,**`If-None-Match`优先级更高**(因`ETag`更精确) - 服务器行为: - 若`ETag`验证通过 → 直接返回`304`(忽略时间戳) - 若`ETag`验证失败 → 再检查`If-Modified-Since` #### 四、应用场景对比 | 场景 | `If-Modified-Since` | `If-None-Match` | |--------------------------|---------------------|-----------------| | 时间戳精度要求高 | ✗ 不适用 | ✓ 适用 | | 资源内容不变时间戳变化 | ✗ 误判失效 | ✓ 准确判断 | | 分布式服务器环境 | ✗ 时间同步问题 | ✓ 稳定适用 | | 简单静态资源缓存 | ✓ 实现简单 | ✓ 更可靠 | | 大文件分块传输 | ✗ 不适用 | ✓ 支持分块验证 | #### 五、最佳实践建议 1. **服务端配置**: - 始终生成`ETag``Last-Modified`响应头 - 对动态内容设置`Cache-Control: no-cache`强制验证 ```nginx # Nginx配置示例 location ~* \.(js|css|png)$ { etag on; add_header Last-Modified ""; } ``` 2. **客户端优化**: - 配合`Cache-Control: max-age=0`实现即时验证 ```http GET /style.css HTTP/1.1 Host: example.com Cache-Control: max-age=0 If-None-Match: "abc123" ``` 3. **性能影响**: - 成功`304`响应可减少90%+带宽(仅传输约150字节头部) - 验证失败时增加约10ms延迟(需完整资源传输) > **关键结论**:现代Web应用应优先采用`ETag/If-None-Match`机制,辅以`Last-Modified/If-Modified-Since`作为降级方案,在保证缓存效率的同时避免"幽灵修改"问题[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值