🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
##浏览器的强制缓存和协商缓存 ### 强制缓存参数 1. **Cache-Control**: * **作用**:控制缓存的行为,是 HTTP/1.1 中最重要的缓存相关头部。 * **常见指令**: * `max-age=<seconds>`: 指定资源在本地缓存中的最大存活时间。 * `no-cache`: 强制要求缓存服务器在返回资源之前验证资源的有效性。 * `no-store`: 禁止缓存存储和提供任何缓存版本。 * **示例**:`Cache-Control: max-age=3600` 2. **Expires**: * **作用**:指定资源的到期时间,是 HTTP/1.0 中定义的字段。 * **注意**:`Expires`是一个具体的到期日期,而`Cache-Control`中的`max-age`是一个相对时间。 ### 协商缓存参数 1. **Last-Modified**: * **作用**:服务器返回资源的最后修改时间。 * **工作原理**:浏览器通过`If-Modified-Since`请求头将上次获取资源的`Last-Modified`时间发送给服务器,服务器根据这个时间判断资源是否有更新。 2. **ETag**: * **作用**:资源的唯一标识符(Entity Tag)。 * **工作原理**:浏览器通过`If-None-Match`请求头将上次获取资源的`ETag`发送给服务器,服务器根据这个标识符判断资源是否有更新。 ### 区别总结 * **强制缓存**通过`Cache-Control`和`Expires`字段控制,浏览器直接根据这些字段判断是否从缓存中获取资源。 * **协商缓存**通过`Last-Modified`和`ETag`字段控制,浏览器通过发送上次获取资源的标识符给服务器,由服务器判断资源是否需要更新。 ### 图解 ![](https://img.kancloud.cn/e0/a5/e0a5fe02377a9e0799199658d05ea94d_1226x1080.webp) ### 问答 ##### 提问:为什么html文件不需要加header头控制,浏览器访问时第二次就是304了,而php文件需要自己处理返回304,html文件的304是谁控制的? 当浏览器访问一个 HTML 文件时,服务器通常会自动处理缓存控制和返回 `304 Not Modified` 状态码,而 PHP 文件则需要开发者手动管理缓存和条件请求。这种区别源于静态文件和动态文件的处理方式不同。 ### HTML 文件的 304 响应 #### 1. **静态文件的处理** HTML 文件通常被视为静态资源,存储在服务器的文件系统中。服务器(如 Apache、Nginx 等)在处理静态文件时,会根据文件的时间戳(例如文件的最后修改时间 `Last-Modified`)和内容的哈希值(如 `ETag`)自动设置响应头。 当浏览器第一次访问这个 HTML 文件时,服务器会返回文件内容,并在响应头中包含 `Last-Modified` 和/或 `ETag` 头。浏览器会缓存该文件以及这些头信息。 #### 2. **浏览器的缓存机制** 在随后的请求中,浏览器会在请求头中附带 `If-Modified-Since` 或 `If-None-Match` 头,这些头信息中包含上次接收到的 `Last-Modified` 或 `ETag` 值。服务器会比较文件的当前时间戳或内容哈希值与请求头中的值: - **如果文件没有变化**(即时间戳或哈希值未变),服务器会返回 `304 Not Modified`,并且不会再次传输文件内容。这减少了带宽消耗。 - **如果文件发生变化**,服务器会返回新的文件内容和状态码 `200 OK`。 这一切都是由服务器软件自动处理的,开发者通常不需要干预。 ### PHP 文件的 304 响应 #### 1. **动态文件的处理** PHP 文件是动态生成的内容,每次请求时 PHP 代码都会被执行并生成新的页面内容。因此,PHP 文件的内容可能每次都不同,服务器无法自动确定文件是否“未修改”。 为了支持 `304 Not Modified` 响应,开发者需要在 PHP 代码中手动实现缓存控制。具体来说: - **手动设置 `Last-Modified` 或 `ETag`**:开发者需要在 PHP 脚本中设置响应头,例如 `Last-Modified` 和 `ETag`,以表明内容的生成时间或哈希值。 - **检查条件请求头**:在处理请求时,开发者需要手动检查请求头中的 `If-Modified-Since` 或 `If-None-Match`,并决定是否返回 `304 Not Modified`。 #### 2. **示例** 以下是一个简单的 PHP 示例,演示如何处理 `304 Not Modified`: ```php <?php // 假设每次生成的内容都有一个固定的时间戳或哈希值 $lastModifiedTime = filemtime(__FILE__); // 这里使用脚本的修改时间作为例子 $etag = md5_file(__FILE__); // 使用文件内容的 MD5 哈希 // 设置响应头 header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastModifiedTime) . " GMT"); header("ETag: \"$etag\""); // 检查 If-Modified-Since 头和 If-None-Match 头 if ((isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModifiedTime) || (isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)) { // 文件未修改,返回 304 header("HTTP/1.1 304 Not Modified"); exit; } // 文件已修改或首次请求,生成内容 echo "<html><body><h1>Hello, World!</h1></body></html>"; ?> ``` ### 总结 - **HTML 文件(静态资源)**:服务器自动处理缓存控制和 `304 Not Modified` 响应。服务器根据文件的时间戳和内容自动生成 `Last-Modified` 和 `ETag` 头,并在条件请求时返回 `304`。 - **PHP 文件(动态资源)**:由于每次请求可能返回不同的内容,服务器无法自动处理 `304 Not Modified` 响应。开发者需要手动设置缓存头并根据条件请求头决定是否返回 `304`。 这种机制有助于提高性能,减少不必要的带宽消耗,并确保浏览器能够正确缓存和更新内容。