项目:zhiyuan App(在线壳 + 资源包架构,Android WebView 壳)。
2026-08-13 排查「大文件下载慢、CDN 好像没加速」。概念底子见 CDN (Content Delivery Network 内容分发网络) 与 Caching Strategies (缓存策略)。

触发条件

CDN 前置的站点上,大文件(资源包 zip、APK)下载慢,怀疑 CDN 没缓存。

症状

  • 15.8MB 资源包、61.5MB APK 下载速度远低于预期,像直连源站。
  • 普通图片/地图(/assets/*)加载正常——说明 CDN 整体在起作用,问题只出在特定大文件上。

根因:源站 Cache-Control 三档

同一站点三类资源,源站给的 Cache-Control 完全不同:

资源源站 Cache-ControlCDN 实际行为
/assets/*(地图/图/JS/CSS)public, max-age=31536000, immutable缓存,但客户端 TTL 被 CDN 规则改写为 max-age=3600
资源包 zip(/api/resource-packs/<id>/archive?version=<hash>)no-store完全不缓存,每回源站流式现打(无 Content-Length)
APK(/download/*.apk)no-cache(无 ETag)每回回源校验,拿不到 304 → 整包重传

三个关键判断:

  1. no-store ≠ no-cache:no-store 禁止一切存储,CDN 直接透传;no-cache 允许存储但每次必须先回源校验。源站若不发 ETag/Last-Modified,校验拿不到 304,退化成整包重传——效果等同没缓存。
  2. 内容寻址 URL 可以 immutable:?version=<hash> 这类参数一变内容必变(content-addressed),按完整 URL 缓存是安全的,不会发版后拿到旧文件。
  3. CDN 会重写源站 Cache-Control:实测源站回 immutable,CDN 回给客户端 max-age=3600——CDN 按自己的缓存规则在盖头。所以只改源站头不一定生效,要先查 CDN 缓存规则是否尊重源站头。

安全边界(容易被忽略)

资源包端点在鉴权闸门之后(JWT),但内容本身是公开静态资源。若把它改成可被 CDN 缓存,等于「知道 URL 就能下到 zip」——CDN 缓存命中不会管请求带没带鉴权头。内容公开则可接受,但属于安全边界口径变化,要同步进安全清单(S04 同源)。

解法(2026-08-13 已落地)

  • 资源包 zip:源站头 no-store → public, max-age=31536000, immutable + ETag: "<version>"(URL 带 version 指纹,内容寻址,immutable 安全)。端点同时移出鉴权闸门改为公开——内容本就是公开静态资源。EdgeOne FollowOrigin 会按源站头缓存。
  • APK:改版本化 URL /download/zhiyuan-app-<version>.apk + public immutable + ETag;固定名旧链接保留为 no-cache 回退(防发版后拿旧包)。resolveApkPath 读 manifest 校验版本名,避免任意文件名访问。
  • 验证前置:先查 CDN 规则是否尊重源站头——本项目 EdgeOne 是 FollowOrigin(遵循源站)、?version= 进完整 URL 缓存键,所以改源站头即生效。若 CDN 是自己盖头(忽略源站 Cache-Control),只改源站没用。

遗留(可选)

  • zip 仍是流式现打(无 Content-Length、不支持 Range)。预生成 zip 文件 + 断点续传可做,不阻塞缓存提速。
  • 图片扩展名规则把 /assets 图片 TTL 压成 3600(EdgeOne 侧配置,未改)。

下次怎么识别

  • 大文件慢、小文件正常 → 查源站大文件响应头是不是 no-store/no-cache。
  • 改了源站头但线上没变化 → curl -sI 对比源站 vs CDN 返回的 Cache-Control,判断 CDN 有没有重写。
  • 判断一个 URL 能不能安全长缓存 → 看它是不是内容寻址(URL/参数变 = 内容变)。

相关


本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web