Yii2 HttpCache 过滤器深度实战:用 Last-Modified、ETag 与 Cache-Control 构建高效的客户端 HTTP 缓存
后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载导读本指南围绕 Yii2 框架内置的yii\filters\HttpCache动作过滤器系统讲解如何在不增加服务端负担的前提下利用 HTTP 协议原生的客户端缓存机制Last-Modified、ETag、Cache-Control三类响应头显著减少同一页面的重复渲染与网络传输。阅读本文后你将掌握HttpCache的完整配置方法、回调签名约定、底层判定逻辑源码级别、与会话缓存的冲突处理方案以及它带来的 SEO 收益能够直接在生产控制器中落地可运行的缓存策略。一、客户端缓存与服务器端缓存互补的加速手段Yii2 之前的章节参见 caching-overview.md、caching-page.md所介绍的数据缓存、片段缓存与页面缓存都属于服务器端缓存——内容生成后仍要从服务器传输给客户端。与之相对Web 应用还可以利用客户端缓存client-side caching让浏览器或代理在本地复用已获取的页面内容从而同时省下服务器端生成页面与通过网络传输页面内容两部分开销。在 Yii2 中启用客户端缓存的方式非常简洁把 [[yii\filters\HttpCache]] 配置为控制器动作action的过滤器filter即可。需要强调的是HttpCache只对GET与HEAD请求生效因为只有这两类请求才可能被客户端安全地缓存见 framework/filters/HttpCache.php 中beforeAction()对请求方法的判断非 GET/HEAD 直接放行它专门管理三类与缓存相关的 HTTP 响应头[[yii\filters\HttpCache::lastModified|Last-Modified]][[yii\filters\HttpCache::etagSeed|Etag]][[yii\filters\HttpCache::cacheControlHeader|Cache-Control]]作为过滤器家族的一员HttpCache通过ActionFilter基类挂载在控制器的behaviors()方法中配合only/except精确圈定作用范围相关通用说明可参见 structure-filters.md。二、Last-Modified头部基于时间戳的命中判定2.1 工作原理Last-Modified响应头用一个时间戳告诉客户端这个页面最近一次修改的时间。客户端通常是浏览器在之后的请求中携带If-Modified-Since请求头回传该时间服务器比对后若发现页面未变化就返回304 Not Modified状态码不重新渲染、不传输正文客户端直接使用本地缓存。2.2 配置方式与回调签名要启用Last-Modified只需配置 [[yii\filters\HttpCache::lastModified]] 属性。该属性必须是返回页面修改时间 UNIX 时间戳的 PHP 可调用对象callable其签名约定如下/** * param Action $action 当前正在处理的动作对象 * param array $params params 属性的值 * return int 代表页面修改时间的 UNIX 时间戳 */ function ($action, $params)其中$params对应HttpCache::params属性可在配置过滤器时额外注入参数用于向回调传递上下文数据详见 framework/filters/HttpCache.php 中$lastModified、$params两个属性的文档注释。2.3 完整示例以文章表最新更新时间作为 Last-Modified下面是最典型的用法——把内容集合的最后修改时间当作页面修改时间public function behaviors() { return [ [ class yii\filters\HttpCache, only [index], lastModified function ($action, $params) { $q new \yii\db\Query(); return $q-from(post)-max(updated_at); }, ], ]; }上述代码通过only [index]将 HTTP 缓存限定在index动作Last-Modified基于post表中updated_at字段的最大值生成。浏览器首次访问index页时服务器正常渲染并返回带Last-Modified的完整响应此后浏览器再次访问时若期间没有任何帖子被修改服务器将直接返回304服务器端渲染与页面内容传输都被跳过。2.4 源码级佐证beforeAction 中的完整判定链从 framework/filters/HttpCache.php 的beforeAction()实现可以看到精确的调用顺序检查$enabled为false时直接放行校验请求方法非 GET/HEAD或lastModified与etagSeed均为空时直接放行若配置了lastModified调用call_user_func($this-lastModified, $action, $this-params)得到时间戳调用sendCacheControlHeader()发送缓存策略头调用validateCache()判断客户端缓存是否仍有效若请求携带If-None-Match则以 ETag 判定且优先于时间戳否则若携带If-Modified-Since则用strtotime(...)解析该头并与$lastModified比较请求时间戳 本地时间戳视为命中缓存有效时设置304状态码并返回false阻止后续动作执行否则照常返回true继续渲染。Last-Modified响应头的格式化输出为gmdate(D, d M Y H:i:s, $lastModified) . GMT符合 HTTP 规范要求的格林尼治标准时间格式。三、ETag头部基于内容哈希的精确缓存3.1 工作原理Entity Tag实体标签简称ETag用页面内容的哈希值表示页面状态内容一旦变化哈希随之改变。服务器把自身生成的哈希与客户端通过If-None-Match请求头回传的哈希比较即可判定页面是否变化、是否需要重新传输比时间戳判定更精确、更灵活。3.2 配置方式与回调签名启用ETag需要配置 [[yii\filters\HttpCache::etagSeed]] 属性一个返回 ETag 哈希种子seed字符串的 PHP 可调用对象签名如下/** * param Action $action 当前正在处理的动作对象 * param array $params params 属性的值 * return string 用于生成 ETag 哈希的种子字符串 */ function ($action, $params)3.3 完整示例以文章标题与内容作为 ETag 种子public function behaviors() { return [ [ class yii\filters\HttpCache, only [view], etagSeed function ($action, $params) { $post $this-findModel(\Yii::$app-request-get(id)); return serialize([$post-title, $post-content]); }, ], ]; }这里将ETag限定在view动作种子由被请求文章通过id查询的title与content序列化而成。浏览器首次访问时正常渲染再次访问且文章标题与内容未变时服务器不重新渲染浏览器直接复用本地缓存。3.4 源码级佐证ETag 的生成算法与弱校验从 framework/filters/HttpCache.php 的generateEtag()可以看到 Yii2 实际采用的哈希算法protected function generateEtag($seed) { $etag . rtrim(base64_encode(sha1($seed, true)), ) . ; return $this-weakEtag ? W/ . $etag : $etag; }即对种子字符串执行SHA-1二进制模式→ Base64 编码并去掉末尾的填充 → 外层包裹英文双引号。同时HttpCache还提供两个值得关注的补充属性自 2.0.8 起引入[[yii\filters\HttpCache::weakEtag|weakEtag]]默认false置为true时生成弱 ETag前缀W/适用于内容语义等价但字节不完全相同的场景符合 RFC 7232 第 2.3 节当etagSeed回调返回null时beforeAction()不会设置ETag响应头测试 tests/framework/filters/HttpCacheTest.php 的testGenerateEtag对此有专门断言。3.5 设计建议与性能警告ETag相比Last-Modified支持更复杂、更精确的缓存策略。例如当站点切换主题时只需在种子表达式中加入主题标识即可让所有页面 ETag 整体失效。但必须警惕ETag 需要在每次请求时重新计算。若种子生成代价过高如复杂的数据库聚合或昂贵的序列化反而会违背HttpCache减少服务端开销的初衷引入不必要负担。因此应尽量选择内容变化时能失效缓存的简单表达式作为种子例如上例中直接复用查询出的字段而不是在回调中再次执行重型计算。3.6 RFC 7232 合规性双头并存时的优先级Note: 依据 RFC 7232若同时配置了ETag与Last-ModifiedHttpCache会同时发送两个响应头。而当客户端同时发送If-None-Match与If-Modified-Since请求头时只有前者If-None-Match会被采纳。这一优先级在源码 framework/filters/HttpCache.php 的validateCache()中有明确体现先检查If-None-Match命中即返回 ETag 比较结果仅在客户端未发送该头时才回退到If-Modified-Since时间戳比较。测试 tests/framework/filters/HttpCacheTest.php 的testValidateCache覆盖了If-None-Match优先于If-Modified-Since、以及通配符*等边界情形。四、Cache-Control头部声明页面级缓存策略Cache-Control响应头用于向客户端浏览器及中间代理声明页面的通用缓存策略——例如是否允许共享缓存、缓存有效时长等。HttpCache通过配置 [[yii\filters\HttpCache::cacheControlHeader]] 属性即可发送自定义值其默认值为Cache-Control: public, max-age3600即允许公共缓存最长缓存 3600 秒1 小时。源码 framework/filters/HttpCache.php 中该属性默认值即为public, max-age3600当显式设为null时sendCacheControlHeader()将不再发送该响应头见同文件 L197-L201。五、会话缓存限制器避免与 PHP Session 的头部冲突5.1 冲突来源当页面使用 Session 时PHP 会根据php.ini中的session.cache_limiter设置自动发送若干缓存相关响应头如Expires、Cache-Control、Last-Modified、Pragma。这些自动头可能与HttpCache精心构造的缓存行为互相干扰甚至直接禁用你想要的缓存效果。5.2 默认行为与自定义为避免冲突HttpCache在默认情况下会自动禁用这些由 PHP 自动发送的缓存头。若想改变此行为可配置 [[yii\filters\HttpCache::sessionCacheLimiter]] 属性取值包括取值含义详见 PHP 手册session_cache_limiter()说明public允许公共缓存通常附带较长的过期时间private仅允许私有浏览器本地缓存private_no_expire私有缓存且不发送Expires头nocache禁用一切缓存每次请求都重新验证源码 framework/filters/HttpCache.php 中该属性默认值为空字符串含义正是关闭 PHP 自动发送缓存头的开关若设为null则不会调用session_cache_limiter()PHP 将按其 INI 配置原样发送缓存头。具体实现位于sendCacheControlHeader()L184-L202当sessionCacheLimiter 且响应头尚未发送、Session 已激活时通过header_remove()移除Expires、Cache-Control、Last-Modified、Pragma四个头再调用Yii::$app-getSession()-setCacheLimiter(...)落实会话缓存限制策略。六、SEO 影响缓存头对搜索引擎爬虫的积极意义搜索引擎的爬虫bot倾向于尊重缓存头。部分爬虫对单域名在单位时间内可抓取的页面数量设有上限因此引入合理的缓存头可以减少爬虫需要真正处理的页面数量从而可能促进站点被更充分地索引。这一收益在页面量大、内容更新不频繁的站点上尤其明显——配合Last-Modified/ETag让爬虫走304分支既能减轻服务器压力也有助于提升抓取效率。七、行为验证从单元测试看 HttpCache 的可靠性仓库中的单元测试 tests/framework/filters/HttpCacheTest.php 对HttpCache的关键行为做了系统覆盖可作为理解与验收缓存配置的参考testDisabledenabled为false时beforeAction()直接返回true即过滤器完全旁路testEmptyPragma使用空字符串作为 ETag 种子时响应中不会出现残留的Pragma头验证了会话缓存限制器的清理逻辑testValidateCache逐条验证If-Modified-Since/If-None-Match的判定矩阵包括时间戳相等命中、哈希不一致未命中、If-None-Match优先、通配符*恒为未命中等场景testGenerateEtag验证 ETag 以双引号包裹、弱 ETag 以W/开头、种子返回null时不发送 ETag 头。八、快速上手清单把HttpCache集成到控制器只需三步在控制器的behaviors()中声明[class yii\filters\HttpCache, ...]并用only/except限定目标动作至少配置lastModified返回 UNIX 时间戳或etagSeed返回种子字符串二者之一——两者都为空时过滤器不生效源码直接放行视需要配置cacheControlHeader默认public, max-age3600与sessionCacheLimiter默认关闭 PHP 自动缓存头并为enabled保留按需动态开关的能力。通过以上配置HttpCache会在每次GET/HEAD请求进入动作前完成缓存校验命中时以304 Not Modified短路响应让客户端复用本地缓存从而真正实现渲染与传输双跳过的高效 HTTP 缓存。赞分享后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载相关推荐Yii2 HTTP 缓存实战借助 HttpCache 过滤器实现 Last-Modified、ETag 与 Cache-Control 客户端缓存Yii2 HTTP 缓存实战借助 HttpCache 过滤器实现 Last Modified、ETag 与 Cache Control 客户端缓存 导读 本指后端Web框架Yii2 HTTP 缓存HttpCache实战指南Last-Modified、ETag 与 Cache-Control 客户端缓存详解Yii2 HTTP 缓存HttpCache实战指南Last Modified、ETag 与 Cache Control 客户端缓存详解 本指南以 Yii后端Web框架Yii 2 HTTP 缓存实战指南用 HttpCache 过滤器实现客户端缓存Last-Modified / ETag / Cache-ControlYii 2 HTTP 缓存实战指南用 HttpCache 过滤器实现客户端缓存Last Modified / ETag / Cache Control H后端Web框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

3个实战项目拆解苇名流考点,面试不再卡壳

3个实战项目拆解苇名流考点,面试不再卡壳

3个实战项目拆解苇名流考点,面试不再卡壳 看了一堆教程还是不会写项目?这大概是很多转行或进阶开发者最真实的痛。你背下了八股文,刷完了算法题,但一遇到【苇名流】相关的底层机制或特定场景的实战项目,脑子就一片空白。…

2026/9/23 13:18:02 阅读更多 →
3个致命误区,局部替换性能优化新手避坑全解

3个致命误区,局部替换性能优化新手避坑全解

3个致命误区,局部替换性能优化新手避坑全解 官方文档翻了三遍还是云里雾里?那种“我知道要改,但不知道改哪里最有效”的无力感,是无数开发者踩过的坑。别被那些长篇大论的理论吓退,局部替换(Local…

2026/9/23 13:18:02 阅读更多 →
造形家搭建风力发电机及风电场三维模型,赋能多行业项目落地

造形家搭建风力发电机及风电场三维模型,赋能多行业项目落地

随着风电新能源项目快速发展,风电场三维场景成为规划设计、数字孪生、方案汇报的重要素材。传统方式需要人工建模或者无人机倾斜摄影,存在周期长、成本高、流程复杂的痛点。造形家作为网页端 AI 三维场地建模工具,依托卫星影像、地形高程数据…

2026/9/23 13:18:02 阅读更多 →

最新新闻

CSS居中与空间分配全解析:从盒模型到Flex/Grid实战

CSS居中与空间分配全解析:从盒模型到Flex/Grid实战

1. 从一次布局翻车说起:为什么居中这么难刚入行那会儿,我接手了一个活动页的改版。设计稿上有一个卡片,要求水平垂直都居中,卡片里还有一行按钮,三个按钮要等宽平分整行。我当时心想,这有什么难的&#xff…

2026/9/23 14:00:58 阅读更多 →
说是避坑指南:Python性能优化5个完整示例实测

说是避坑指南:Python性能优化5个完整示例实测

说是避坑指南:Python性能优化5个完整示例实测 配置环境就卡半天,跑个脚本要等半分钟,这种折磨谁懂?别急着换机器,多半是代码写法太“业余”。今天不聊虚的,直接上 完整示例 ,把那些说是能提速90%的优化手段,一个个跑给你看。…

2026/9/23 14:00:58 阅读更多 →
绝地求生吃鸡图片实战项目:3步搞定跑不通代码的调试心法

绝地求生吃鸡图片实战项目:3步搞定跑不通代码的调试心法

绝地求生吃鸡图片实战项目:3步搞定跑不通代码的调试心法 刚把网上扒下来的“绝地求生吃鸡图片”生成脚本复制下来,双击运行,黑框一闪而过或者直接报错 ModuleNotFoundError…

2026/9/23 14:00:58 阅读更多 →
Python电商评论情感分析实战:从数据清洗到模型部署

Python电商评论情感分析实战:从数据清洗到模型部署

简介:这份资源包面向Python开发者与高校学生,提供一套完整的电商买家评论情感分析实战项目,可用于毕业设计、课程设计或NLP入门练习。包内共860个文件,以478个py源码、37个csv评论数据集、81个h头文件及dll、pyd等依赖库为主&…

2026/9/23 14:00:58 阅读更多 →
SpaceX-API Landing Pad 数据模型详解:v4 Schema 字段全解析与查询实战

SpaceX-API Landing Pad 数据模型详解:v4 Schema 字段全解析与查询实战

SpaceX-API Landing Pad 数据模型详解:v4 Schema 字段全解析与查询实战 【免费下载链接】SpaceX-API :rocket: Open Source REST API for SpaceX launch, rocket, core, capsule, starlink, launchpad, and landing pad data. 项目地址: https://gitcode.com/gh_m…

2026/9/23 14:00:58 阅读更多 →
Simulink建模必知:Inport模块图标形态与工程语义全解析

Simulink建模必知:Inport模块图标形态与工程语义全解析

最近在帮几个做电机控制仿真的朋友梳理Simulink模型,发现好多人在Inport模块上面栽了跟头——不是端口连不上,就是生成代码之后信号对不上,甚至有人根本不知道同一个Inport在不同的使用场景下会显示成完全不同的图标样式。今天我就把这几年在…

2026/9/23 13:59:58 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →