HTTP 条件请求中 ETag 与 Last-Modified 如何配合使用
HTTP 条件请求通过 Last-Modified 日期或 ETag 字符串来验证资源版本,浏览器在缓存过期时会发送 If-Modified-Since 或 If-None-Match 头部,服务器据此返回 304 状态码以节省带宽。
条件请求如何通过版本标识符判断资源是否变更
HTTP 条件请求的核心在于通过特定的头部值来验证服务器上的资源版本是否发生变化。为了实现这一点,请求中必须包含一个描述资源版本的值,这些值被称为验证器。验证器主要分为两种类型:一种是文档最后修改的日期,即 Last-Modified 日期;另一种是唯一标识每个版本的不可 opaque 字符串,称为实体标签,即 ETag。当浏览器缓存过期后,它会使用这些验证器来发送条件请求,从而避免传输整个资源。
比较两个版本的逻辑取决于具体的验证类型。强验证要求资源在字节层面完全一致,例如在断点续传下载时需要确保数据无损。弱验证则允许资源在内容上存在细微差异,例如页脚日期不同或广告内容变化,只要核心内容相同即可视为一致。HTTP 默认使用强验证,但同时也支持在特定场景下使用弱验证。Last-Modified 和 ETag 都支持这两种验证方式,但服务器端实现这两种验证的复杂程度可能有所不同。
Last-Modified 与 ETag 在缓存更新中的具体工作流程
在缓存更新的场景中,条件请求被广泛用于提高效率。当浏览器首次请求资源时,服务器会返回资源内容以及 Last-Modified 和 ETag 头部。这些验证器会被浏览器缓存起来。当缓存过期后,浏览器不会直接使用缓存数据,而是发送一个条件请求,将缓存的 Last-Modified 日期放入 If-Modified-Since 头部,或将缓存的 ETag 放入 If-None-Match 头部。
服务器收到请求后,会检查资源的实际版本与请求中提供的验证器是否匹配。如果资源未发生变化,服务器将返回 304 Not Modified 状态码,浏览器则继续使用本地缓存。如果资源已发生变化,服务器将返回 200 OK 状态码以及新的资源内容。这种机制避免了每次都传输完整的资源数据,从而节省了带宽。值得注意的是,Last-Modified 和 ETag 通常会同时发送,但并非必须,具体取决于服务器的配置。
如何排查条件请求未生效或缓存未更新的问题
如果发现浏览器没有发送条件请求,或者服务器总是返回 200 而不是 304,可以按照以下步骤进行排查。首先,检查服务器是否正确配置了 Last-Modified 和 ETag 头部。可以使用开发者工具查看响应头,确认这两个字段是否存在且值正确。如果服务器使用了压缩,需要确认 ETag 是否在压缩后发生了变化,因为内容编码的改变通常需要更新 ETag。
其次,检查浏览器缓存的状态。在开发者工具的 Network 面板中,查看请求的 Status Code 是否为 304。如果状态码是 200,说明条件请求可能未生效。此时可以尝试清除浏览器缓存,或者强制刷新页面(Ctrl+F5),然后重新观察请求。如果问题依然存在,可能是服务器端的时间设置错误,导致 Last-Modified 日期不准确,或者 ETag 的生成逻辑存在问题。
验证条件请求配置是否正确的检查方法
要验证条件请求的配置是否正确,可以通过模拟请求来测试。在开发者工具的 Network 面板中,勾选 Disable cache 选项,然后刷新页面。观察请求的头部,确认是否包含了 If-Modified-Since 或 If-None-Match 头部。如果这些头部存在,说明浏览器已经正确地发送了条件请求。
接下来,查看服务器的响应。如果资源未发生变化,响应的状态码应为 304,且响应体应为空。如果响应体不为空或状态码为 200,说明条件请求可能未生效。此时可以检查服务器的日志,确认服务器是否正确处理了条件请求。如果服务器返回 412 Precondition Failed,说明验证器不匹配,可能是 ETag 或 Last-Modified 的值不正确。
资料与延伸阅读
你可以通过以下原始资料核对文中概念,并继续深入阅读。