一次CDN缓存不同的问题 oral/oss/amazon/aliyun

记一次 CDN 的目录式路径 与 文件路径不同导致的线上问题

2个关键的 curl

$ curl -I https://webapp.alo7.com/oral-assignment/
HTTP/2 200 
server: Tengine
content-type: text/html
content-length: 3797
x-amz-id-2: 07VDcAu/UNbtXYFd0E1MLp3dm7EfesOu98ORDggytKySVJvpYXEFqhp1eZgrNpi8OWtqkJMTx+k=
x-amz-request-id: FEJ7SY68CRGDWTCY
date: Tue, 19 Aug 2025 03:19:17 GMT
cache-control: private, no-cache, no-store, must-revalidate
via: cache49.l2cn8116[69,68,304-0,H], cache14.l2cn8116[70,0], kunlun1.cn7174[80,80,200-0,H], kunlun9.cn7174[82,0]
last-modified: Fri, 08 Aug 2025 06:10:15 GMT
etag: "d75d15eb6bcab0dbf45442388d8b2770"
age: 0
ali-swift-global-savetime: 1755573556
x-cache: HIT TCP_REFRESH_HIT dirn:-2:-2
x-swift-savetime: Tue, 19 Aug 2025 03:19:16 GMT
x-swift-cachetime: 0
access-control-allow-origin: *
timing-allow-origin: *
eagleid: b4a3921d17555735568152359e


~/Downloads via 🐠 v20.19.2 
$ curl -I https://webapp.alo7.com/oral-assignment/index.html
HTTP/2 200 
server: Tengine
content-type: text/html
content-length: 3797
x-amz-id-2: MoQBHk6vrxFYy60Gn/hH7chogy7YkPfQGPKansSoBacUOqjRBbNmvBuQLRccD0aEZxpqFssAUSw=
x-amz-request-id: 56FWRGEQ3E423KYY
date: Tue, 19 Aug 2025 03:19:22 GMT
cache-control: private, no-cache, no-store, must-revalidate
last-modified: Tue, 19 Aug 2025 02:59:13 GMT
etag: "d75d15eb6bcab0dbf45442388d8b2770"
via: cache32.l2cn8116[73,73,200-0,M], cache35.l2cn8116[75,0], kunlun1.cn7174[84,85,200-0,M], kunlun3.cn7174[86,0]
ali-swift-global-savetime: 1755573561
x-cache: MISS TCP_MISS dirn:-2:-2
x-swift-savetime: Tue, 19 Aug 2025 03:19:21 GMT
x-swift-cachetime: 0
access-control-allow-origin: *
timing-allow-origin: *
eagleid: b4a3921717555735610351263e

你观察到两个 URL:

  • https://webapp.alo7.com/oral-assignment/(目录式路径)
  • https://webapp.alo7.com/oral-assignment/index.html(具体文件路径)

虽然它们返回的内容类型和大小相同(content-length: 3797etag: "d75d15eb6bcab0dbf45442388d8b2770"),但 Last-Modified 时间不同

  • 前者:Fri, 08 Aug 2025 06:10:15 GMT
  • 后者:Tue, 19 Aug 2025 02:59:13 GMT

这看起来矛盾:同一个文件,为什么 Last-Modified 不同?


🔍 原因分析

尽管内容和 ETag 一致,表明最终返回的 HTML 内容是一样的,但 Last-Modified 头部不同,说明这两个请求在服务器或 CDN 处理流程中 被视为不同的资源或由不同机制生成

以下是可能的根本原因:


✅ 1. 服务器端动态生成 index.htmlLast-Modified

  • /oral-assignment/ 是一个目录路径,服务器在收到请求时会自动查找默认首页(如 index.html),然后动态生成响应头
  • 此时,Last-Modified 可能取自服务器内部配置文件、路由时间、缓存生成时间,而非真实文件。
  • 而直接访问 /oral-assignment/index.html 时,CDN 或后端识别为具体静态资源,使用该文件在对象存储中的真实上传/修改时间。

⚠️ 这意味着:两个请求虽然返回相同内容,但元数据(如 Last-Modified)可能来自不同来源。


✅ 2. CDN/反向代理行为差异

从响应头看,使用了阿里云 Tengine + CDN(via: kunlun, ali-swift-global-savetime)。

  • /oral-assignment/ 的请求:

    • x-cache: HIT TCP_REFRESH_HIT → 从缓存命中
    • last-modified: Fri, 08 Aug 2025 → 可能是原始缓存条目的时间戳,未刷新元数据
  • /oral-assignment/index.html 的请求:

    • x-cache: MISS TCP_MISS → 缓存未命中,回源拉取
    • last-modified: Tue, 19 Aug 2025 → 更接近真实文件时间(可能是新上传的)

👉 所以:/ 路径命中的是旧缓存条目,其 Last-Modified 没有随内容同步更新,而直接访问 index.html 触发了回源,获取了更新后的元数据。


✅ 3. 静态资源部署时未同步更新所有路径的元数据

假设部署系统只上传了 index.html 文件,但没有清除所有相关缓存或更新目录索引的元信息:

  • /oral-assignment/index.htmlLast-Modified 正确反映最新上传时间(2025-08-19)
  • /oral-assignment/ 对应的“虚拟目录索引”仍保留旧的 Last-Modified(2025-08-08)

类似于:文件内容更新了,但目录列表的时间戳没更新。


✅ 4. ETag 相同说明内容一致,Last-Modified 不同仅说明元数据来源不同

  • ETag: "d75d15eb..." 完全相同 → 内容确实一致
  • Last-Modified元数据,不是内容指纹
  • 因此:内容相同 ≠ 元数据相同

🧩 总结:为什么 Last-Modified 不同?

| 原因 | 说明 |
|------|------|
| 📁 路径处理机制不同 | 目录访问 / 是服务器自动映射到 index.html,元数据可能不准确 |
| ☁️ CDN 缓存策略差异 | / 路径命中旧缓存,index.html 路径回源,获取新元数据 |
| ⏱️ 元数据未同步更新 | 部署新版本时,目录路径的 Last-Modified 未刷新 |
| ✅ 内容实际一致 | ETagContent-Length 一致,说明文件内容无差别 |


✅ 建议解决方案

  1. 统一清除缓存:部署后清除 /oral-assignment//oral-assignment/index.html 的 CDN 缓存。
  2. 使用版本化路径或查询参数:避免依赖 Last-Modified 做更新判断。
  3. 优先使用 ETag 进行缓存校验:比 Last-Modified 更可靠。
  4. 检查服务器配置:确保目录索引返回的 Last-Modified 与实际文件一致。

📌 结论

Last-Modified 不同,是因为两个 URL 在 CDN/服务器处理链中被视为不同资源路径,导致元数据来源不同;但 ETag 一致,说明返回的内容是相同的。这不是文件不同,而是元数据同步或缓存机制不一致所致。

你可以放心,内容是一样的,但若依赖 Last-Modified 做缓存或更新判断,建议改用 ETag