导读:本期聚焦于小黄人创作的《如何在Apache中正确配置浏览器强缓存与协商缓存?》,敬请观看详情。当网站静态资源频繁被重复请求却每次都返回完整数据,带宽和响应时间都会无谓损耗。Apache通过ExpiresFilter、mod_expires与mod_headers可分别设置强缓存及协商缓存。强缓存依靠Expires或Cache-Control令浏览器在有效期内不发起请求,协商缓存则借助Last-Modified与ETag由服务器判定304还是200。实际部署时常因配置顺序错误导致header被覆盖,或ETag与压缩模块冲突而失效。理解文件系统时间戳、inode差异以及Cache-Control的max-age语义,才能针对CSS、图片、接口文档给出稳妥策略,在更新即时性与命中率之间取得平衡。

在Web性能优化体系中,缓存是降低延迟与节省带宽的核心手段。Apache作为最广泛使用的Web服务器之一,提供了多种模块来控制浏览器端的强缓存与协商缓存行为。强缓存是指浏览器在资源有效期内完全不向服务器发请求,直接读取本地副本;协商缓存则是浏览器每次都发送条件请求,由服务器通过时间戳或内容标识判断资源是否变化,未变化则返回304状态码。这两种机制在Apache中可以通过不同指令组合实现,但配置细节容易混淆,导致缓存失效或更新不及时。

如何在Apache中正确配置浏览器强缓存与协商缓存?

强缓存的配置原理与mod_expires实战

强缓存的实现依赖于响应头中的ExpiresCache-Control。Apache的mod_expires模块能基于文件类型自动计算过期时间,并生成Expires头以及对应的Cache-Control: max-age。其底层逻辑是:当请求到达时,Apache根据配置规则匹配MIME类型,在响应发出前注入未来某个时间点的绝对过期值,同时换算为相对秒数写入Cache-Control。浏览器接到此类头后,在max-age秒内不会再次联系服务器,哪怕用户刷新页面(部分浏览器F5会忽略强缓存,但地址栏回车或外链引用仍生效)。

下面是一个典型的mod_expires配置片段,通常写在虚拟主机或.htaccess中:

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access plus 30 days"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType application/javascript "access plus 7 days"
    ExpiresByType image/png "access plus 1 year"
</IfModule>

上述配置表示CSS缓存30天,JS缓存7天,图片缓存一年。需要注意access plus是以请求时间为起点计算,若改为modification则基于文件最后修改时间。如果文件更新频繁但配置了一年强缓存,用户将无法及时获取新版本,此时往往需要配合文件名加哈希(如app.abc123.js)来突破缓存。另外,mod_headers可用来更精细地控制Cache-Control的其它指令,例如no-transformpublic,避免代理服务器错误转换内容。

使用强缓存的优势是零请求开销,特别适合图标、字体等几乎不变的静态资源。但其缺点也明显:一旦发布急需修正的错误,旧用户可能长期持有错误副本。因此实践中通常对带版本号的文件设长缓存,对入口HTML设短缓存或不缓存,以兼顾速度与更新。

协商缓存的机制与ETag、Last-Modified设置

协商缓存并不阻止浏览器发请求,而是借助Last-ModifiedETag两个头完成验证。Apache默认通过mod_core发送Last-Modified,其值来自文件系统的mtime。当浏览器再次请求时,会带上If-Modified-Since,Apache比对时间,若未改变则返回304。而ETagmod_file_cache或默认核心生成,一般是文件inode、大小、mtime的哈希,能更精准识别内容变化,因为某些情况(如上传覆盖但mtime不变)下时间戳并不可靠。

以下示例展示如何用mod_headers确保协商头存在,并移除可能引发问题的默认ETag(再自定义):

<IfModule mod_headers.c>
    Header unset ETag
    FileETag None
    Header set Last-Modified "%{LAST_MODIFIED}e" env=LAST_MODIFIED
</IfModule>

在某些集群环境中,多台机器的inode不同会导致同一文件ETag不一致,从而使协商缓存失效并引发重复下载。此时可设置FileETag MTime Size仅用大小和修改时间生成标识,或完全关闭ETag改用Last-Modified。浏览器在收到304后,直接从本地缓存读取旧体,网络传输仅几十字节头部,大幅减少流量。协商缓存适合内容可能变化但又希望复用本地副本的场景,例如用户头像、API JSON(配合正确头)。

需要警惕的是,若同时开启mod_deflate压缩,ETag可能因编码方式不同而被Apache改写为弱验证器(以W/开头),这虽符合HTTP规范,但部分旧CDN兼容性差。此时可关闭压缩对静态文件的ETag影响,或统一在源站处理好再分发。

配置冲突排查与综合策略建议

实际部署时常出现强缓存与协商缓存互相覆盖的情况。例如先由mod_expires写入Cache-Control: max-age=0,随后mod_headers又追加max-age=3600,由于Apache指令合并顺序,最终头可能变成max-age=0, max-age=3600让浏览器无所适从。排查时应使用curl -I查看真实响应头,并确认各模块加载顺序,必要时用Header mergeHeader set明确覆盖而非追加。

下面是一段综合配置,对HTML短缓存、对静态资源长强缓存并保留协商头作为兜底:

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/html "access plus 0 seconds"
    ExpiresByType image/* "access plus 1 year"
</IfModule>
<IfModule mod_headers.c>
    <FilesMatch ".(js|css)$">
        Header set Cache-Control "max-age=604800, public"
    </FilesMatch>
    Header merge Cache-Control "no-cache" env=NEED_REVALIDATE
</IfModule>

该策略让图片一年不强请求,JS和CSS一周强缓存但同时允许服务器重新验证。当运维发现某CSS有BUG时,可通过设置环境变量NEED_REVALIDATE让相关请求带no-cache,迫使浏览器走协商,快速修复线上问题而不必改文件名。总体而言,理解Apache各指令生效阶段、合理组合模块,才能构建既高效又可控的缓存体系。

最后强调,任何缓存配置都应在预发布环境用多浏览器验证,尤其注意移动端WebView对Cache-Control的解析差异。只有将强缓存的零延迟与协商缓存的安全性结合,才能在高并发站点中真正提升用户体验。

Apache强缓存协商缓存修改时间:2026-08-18 01:12:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。