mod_cache 默认不缓存 range 请求,因其以完整响应为缓存单位,缓存206会导致内容不完整和行为不一致;需用cacheignoreheaders range(apache 2.4.13+)配合强etag和accept-ranges支持。

Apache HTTP Server 的 mod_cache 模块默认**不缓存 Range 请求的响应**(即带 Range: bytes=... 头的请求),即使源服务器返回了 206 Partial Content 和有效的缓存头。这是由设计决定的安全与语义一致性考量,而非配置遗漏。
为什么 mod_cache 默认跳过 Range 请求?
Range 请求本质是“部分资源获取”,而 mod_cache(尤其是 mod_disk_cache 或 mod_mem_cache)以完整响应为缓存单位。缓存一个 206 响应会导致两个问题:
- 缓存内容不完整(只存了某一段字节),后续其他 Range 请求无法复用;
- 若缓存了 206 响应却未同时缓存 200 响应,客户端发起全量请求时可能击不中缓存,造成行为不一致。
因此,mod_cache 在收到含 Range 请求头的请求时,会直接 bypass 缓存逻辑,转交后端处理(除非显式干预)。
如何让 Range 请求也能利用缓存?
核心思路不是“缓存 206 响应”,而是**确保 Range 请求能命中已缓存的完整资源(200 响应)并由 Apache 自动切片返回**——这需要启用 mod_cache 配合 mod_cache_disk(或 mod_cache_socache)以及关键模块 mod_file_cache 或更推荐的 mod_cache + mod_headers + 后端协作。但真正可行且标准的方式是:
-
启用
CacheIgnoreHeaders Range:该指令告诉mod_cache忽略Range请求头对缓存决策的影响(仅适用于 Apache 2.4.13+)。配合后端返回带Accept-Ranges: bytes和强校验(ETag或Last-Modified)的 200 响应,Apache 可在缓存中找到完整资源后,自行处理 Range 切片并返回 206; -
确保后端返回可缓存的完整响应:Java 应用(如 Spring Boot、Tomcat)需对静态资源或大文件接口设置:
Cache-Control: public, max-age=3600Accept-Ranges: bytesETag: "abc123"(强 ETag 更佳); -
禁用不兼容的中间处理:避免在 Java 层手动写 206 响应(如用
HttpServletResponse设置状态码和Content-Range),应让容器(如 Tomcat)或反向代理(Apache)原生支持 Range;Tomcat 8.5+ 默认开启sendfile和 Range 支持,无需额外代码。
验证是否生效
通过 curl 观察响应头:
curl -I -H "Range: bytes=0-1023" http://your-server/file.mp4
成功时应看到:
- 状态码
206 Partial Content; - 响应头含
X-Cache: HIT(如果启用了mod_cache并配置了CacheIgnoreHeaders Range); - 不含
X-Cache: MISS或后端标识(如X-Powered-By: Java)。
若仍为 MISS,检查日志中是否有 cache: range request ignored 类提示,并确认 Apache 版本 ≥ 2.4.13 且配置已重载。
替代方案:用 mod\_proxy\_cache + origin 支持
若 Apache 版本较低或无法升级,可将 Range 处理交给后端 Java 服务,仅用 mod_proxy_cache 缓存 200 响应。此时需 Java 接口主动支持 Range(如 Spring Web 的 ResourceHttpRequestHandler 已内置支持),Apache 仅作透明缓存代理,不参与切片。这种方式更稳定,但要求 Java 层正确实现 ETag/Last-Modified 校验和 206 生成。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










