news 2026/9/23 3:06:31

Yii2 缓存机制全面解析:数据缓存、查询缓存、片段缓存、页面缓存与 HTTP 缓存实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Yii2 缓存机制全面解析:数据缓存、查询缓存、片段缓存、页面缓存与 HTTP 缓存实战指南
  • 后端
  • Web框架

【免费下载链接】yii2

Yii 2: The Fast, Secure and Professional PHP Framework

项目地址:https://gitcode.com/gh_mirrors/yi/yii2
点击查看免费下载

缓存是 Web 应用提升性能的一种廉价而有效的手段:把相对静态的数据存入缓存,在请求到来时直接由缓存返回,从而省去每次从零生成数据的开销。本文以 Yii2 官方指南的缓存章节(docs/guide-ja/caching-overview.md)为核心骨架,系统梳理 Yii2 在服务器端与客户端提供的全部缓存机制——数据缓存、片段缓存、页面缓存与 HTTP 缓存,并结合 framework/caching 目录下的源码实现深入讲解其底层原理与配置要点。读完本文,你将掌握从缓存组件配置、缓存键设计、过期与依赖失效,到查询缓存、片段缓存嵌套、动态内容以及基于Last-Modified/ETag的 HTTP 缓存的一整套实战方案。

缓存发生在哪里:层级与位置

缓存可以在 Web 应用的不同层级和位置发挥作用:

  • 服务器端低层:用于保存基础数据,例如从数据库查询出来的最新文章信息列表;
  • 服务器端高层:用于保存网页的片段乃至整个页面,例如最新文章的渲染结果;
  • 客户端:通过 HTTP 缓存,让浏览器缓存最近访问过的页面内容,下次访问时直接复用。

Yii2 对以上所有缓存机制均提供开箱即用的支持,官方文档将其归纳为四类:

机制作用对象核心实现对应指南章节
数据缓存(Data Caching)PHP 变量yii\caching\Cache及其子类caching-data.md
片段缓存(Fragment Caching)页面片段yii\base\View::beginCache()/yii\widgets\FragmentCachecaching-fragment.md
页面缓存(Page Caching)整个页面yii\filters\PageCache动作过滤器caching-page.md
HTTP 缓存(HTTP Caching)浏览器端内容yii\filters\HttpCache动作过滤器caching-http.md

从源码目录看,Yii2 在 framework/caching 下集中实现了统一的缓存抽象:基类Cache实现了CacheInterface,并为ApcCacheArrayCacheDbCacheDummyCacheFileCacheMemCacheWinCache等不同存储后端预留了getValue()setValue()addValue()deleteValue()flushValues()五个抽象方法;依赖体系则由Dependency基类与ChainedDependencyDbDependencyDbQueryDependencyExpressionDependencyCallbackDependencyFileDependencyTagDependency构成。

数据缓存(Data Caching)

数据缓存是最基础的缓存形态,它把某个 PHP 变量存入缓存,之后再从缓存中取回;它同时也是查询缓存、页面缓存等高级特性的基石。

典型用法

假定$cache指向一个缓存组件,典型的使用模式如下:

// 尝试从缓存中取出 $data $data = $cache->get($key); if ($data === false) { // 缓存中不存在 $data,从头计算 $data = $this->calculateSomething(); // 存入缓存,供下次取用 $cache->set($key, $data); } // 此时 $data 已经可用

自 Yii 2.0.11 起,缓存组件提供了getOrSet()方法(见 framework/caching/CacheInterface.php),把"取数据、算数据、存数据"三步合并成一次调用,与上面示例完全等价:

$data = $cache->getOrSet($key, function () { return $this->calculateSomething(); });

当缓存中存在该$key对应的数据时直接返回缓存值;否则执行传入的匿名函数,将其返回值写入缓存并返回。若匿名函数需要用到外部作用域的变量,用use语句传入即可:

$user_id = 42; $data = $cache->getOrSet($key, function () use ($user_id) { return $this->calculateSomething($user_id); });

注意:getOrSet()同样支持过期时长(duration)和依赖(dependency)参数,详见后文"缓存过期"与"缓存依赖"两节。

缓存组件:统一抽象,随时可替换

数据缓存依赖所谓的"缓存组件"(cache component),它们代表了不同的缓存存储介质——内存、文件、数据库等。缓存组件通常注册为应用组件(参见 structure-application-components.md),从而可以全局配置、随处访问。下面的配置让cache应用组件使用带两台服务器的 Memcached:

'components' => [ 'cache' => [ 'class' => 'yii\caching\MemCache', 'servers' => [ [ 'host' => 'server1', 'port' => 11211, 'weight' => 100, ], [ 'host' => 'server2', 'port' => 11211, 'weight' => 50, ], ], ], ],

配置完成后,即可通过Yii::$app->cache访问该缓存组件。若未显式配置任何缓存组件,Yii2 默认使用yii\caching\FileCache

由于所有缓存组件都实现同一套 API,你可以仅修改应用配置就切换到另一种缓存后端,而不必改动任何使用缓存的业务代码。例如将上面配置切换为 APC 缓存:

'components' => [ 'cache' => [ 'class' => 'yii\caching\ApcCache', ], ],

提示:可以在应用中注册多个缓存组件,但名为cache的组件会被大量依赖缓存的类(如yii\web\UrlManager)默认使用。

支持的缓存存储一览

Yii2 支持广泛的缓存存储,framework/caching 目录下每一种实现对应一个类:

缓存类存储介质适用场景与注意事项
yii\caching\ApcCachePHP APC/APCu 扩展集中式胖应用(单服务器、无独立负载均衡)场景下可视为最快选择
yii\caching\DbCache数据库表必须按DbCache::cacheTable的约定创建缓存表
yii\caching\ArrayCache进程内数组仅在当前请求内有效;将serializer设为false可进一步提升性能
yii\caching\DummyCache无(占位)不做真实缓存;便于统一代码写法,开发期或后端无缓存时使用,切换后端时无需改业务代码
yii\caching\FileCache标准文件特别适合缓存大块数据,如页面内容
yii\caching\MemCachememcache/memcached 扩展分布式应用(多服务器、负载均衡)场景下可视为最快选择
yii\redis\CacheRedis 键值存储需要 Redis 2.6.12 及以上版本(该扩展类在独立的 redis 扩展包中)
yii\caching\WinCachePHP WinCache 扩展Windows 环境

提示:同一应用中可以混用不同缓存存储。常见的策略是:用内存型缓存保存"小而高频"的数据(如统计数据),用文件型或数据库型缓存保存"大而低频"的数据(如页面内容)。

缓存 API

所有缓存组件都继承自基类 framework/caching/Cache.php,支持以下统一 API:

方法作用
get($key)按键取回数据;未命中、过期或依赖失效时返回false
set($key, $value, $duration = null, $dependency = null)按键存储数据(已存在则覆盖)
add($key, $value, $duration = 0, $dependency = null)仅当键不存在时存储
getOrSet($key, $callable, $duration = null, $dependency = null)命中返回缓存值,未命中执行回调并缓存其返回值
multiGet($keys)批量取回多个键的数据
multiSet($items, $duration = null, $dependency = null)批量存储多个键值对
multiAdd($items, $duration = 0, $dependency = null)批量存储,已存在的键跳过
exists($key)判断指定键是否存在
delete($key)删除指定键的数据
flush()清空缓存中全部数据

注意:不要直接把布尔值false作为数据缓存,因为get()false表示"未命中"。如需缓存false,可将其放入数组中再缓存。

MemCache、APC 等存储支持一次批量取回多个值,可降低取数开销;multiGet()/multiAdd()正是为利用该特性而提供的,若底层存储不支持,框架会自动降级为逐个操作(参见 framework/caching/Cache.php 中getValues()的默认实现)。

由于Cache实现了ArrayAccess接口,缓存组件可以直接像数组一样使用:

$cache['var1'] = $value1; // 等价于 $cache->set('var1', $value1); $value2 = $cache['var2']; // 等价于 $value2 = $cache->get('var2');

缓存键的设计

缓存中的每条数据都通过一个键(key)唯一标识。键可以是字符串,也可以是任意值——非字符串的键会被自动序列化。

一种常见的键设计策略是把所有决定性因素放进一个数组。例如yii\db\Schema缓存数据库表结构信息时使用的键:

[ __CLASS__, // schema 类名 $this->db->dsn, // 数据库连接的数据源名称 $this->db->username, // 数据库登录用户 $name, // 表名 ];

可见该键囊括了唯一定位一张数据库表所需的全部信息。

注意:通过multiSet()/multiAdd()批量存储时,键只能是字符串或整数;若需要更复杂的键,请改用set()/add()逐条存储。

当多个应用共用同一个缓存存储时,应为每个应用设置唯一的keyPrefix,避免键冲突。在应用配置中这样设置:

'components' => [ 'cache' => [ 'class' => 'yii\caching\ApcCache', 'keyPrefix' => 'myapp', // 唯一的缓存键前缀 ], ],

为确保互操作性,前缀应只使用字母数字字符。

从源码看键的规范化逻辑在 framework/caching/Cache.php 的buildKey()方法中:纯字母数字且长度不超过 32 的字符串键直接加前缀返回;其余情况(含非字符串键)会先序列化再做 MD5 哈希,再拼接前缀。

缓存过期(Expiration)

默认情况下,缓存项会一直保留,除非被缓存策略清除(如空间写满后淘汰最旧数据)。要改变这一行为,可在set()时传入过期时长参数,表示该数据项在缓存中有效多少秒;超过有效期后get()返回false。例如:

// 让数据在缓存中最多保留 45 秒 $cache->set($key, $data, 45); sleep(50); $data = $cache->get($key); if ($data === false) { // $data 已过期或未命中 }

自 2.0.11 起,可以在缓存组件配置中设置defaultDuration作为全局默认时长(framework/caching/Cache.php),这样每次调用set()时无需再显式传duration参数。默认值为0,表示永不过期;set()在未显式传时长时会回退到该值(framework/caching/Cache.php)。

缓存依赖(Dependencies)

除了过期时间,缓存数据还可以通过"缓存依赖"来失效。例如yii\caching\FileDependency表示依赖某个文件的修改时间——当依赖的文件被修改时,缓存中对应的旧内容应失效,get()返回false

缓存依赖是yii\caching\Dependency子类的对象(基类见 framework/caching/Dependency.php)。调用set()存储数据时可将依赖对象一并传入:

// 创建对 example.txt 修改时间的依赖 $dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']); // 数据 30 秒后过期;若 example.txt 在此期间被修改,也会提前失效 $cache->set($key, $data, 30, $dependency); // 取出时既检查是否过期,也检查关联依赖是否变化 // 任一条件满足都会返回 false $data = $cache->get($key);

从 framework/caching/Cache.php 的get()实现可以看到依赖校验的底层逻辑:存入时set()调用$dependency->evaluateDependency($cache)把当时的依赖快照与数据一起序列化存储(framework/caching/Cache.php);取出时反序列化后调用$dependency->isChanged($cache)重新生成最新依赖数据并与快照比对,一旦不一致即视为失效(framework/caching/Dependency.php)。

Yii2 内置的缓存依赖如下:

依赖类失效条件
yii\caching\ChainedDependency链上任意一个依赖发生变化
yii\caching\DbDependency指定 SQL 语句的查询结果发生变化
yii\caching\ExpressionDependency指定 PHP 表达式的求值结果发生变化
yii\caching\CallbackDependency指定 PHP 回调的返回结果发生变化
yii\caching\FileDependency文件最后修改时间发生变化
yii\caching\TagDependency通过TagDependency::invalidate()显式按标签失效

其中TagDependency是实用性很高的一种:它把缓存项与一个或多个标签关联,之后可以一次性按标签批量失效。源码示例(framework/caching/TagDependency.php):

// 将多个键打上 "user-123" 标签永久缓存 Yii::$app->cache->set('user_42_profile', '', 0, new TagDependency(['tags' => 'user-123'])); Yii::$app->cache->set('user_42_stats', '', 0, new TagDependency(['tags' => 'user-123'])); // 使所有带 "user-123" 标签的键失效 TagDependency::invalidate(Yii::$app->cache, 'user-123');

其原理(framework/caching/TagDependency.php)是为每个标签在缓存中维护一个时间戳键,invalidate()会重写这些时间戳,从而让所有依赖该标签的数据快照比对失败。

注意:不要对带依赖的缓存使用exists()方法,它不检查关联依赖是否变化,可能出现get()返回falseexists()返回true的情况。

警告:缓存值通过 PHP 原生serialize()/unserialize()存储和读取(含所附的Dependency对象)。应把缓存后端视为可信存储,绝不能让不可信方写入缓存——反序列化构造的恶意字节可能实例化任意对象,详见 security-best-practices.md 中关于避免不安全反序列化的说明。

查询缓存(Query Caching)

查询缓存是构建在数据缓存之上的一种特殊缓存,专门用于缓存数据库查询结果。

查询缓存需要满足两个前提:一个yii\db\Connection数据库连接,以及一个有效的cache应用组件。基本用法如下,假设$dbyii\db\Connection实例:

$result = $db->cache(function ($db) { // 若查询缓存已启用且结果命中缓存,SQL 查询结果将直接从缓存返回 return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne(); });

查询缓存对 DAO(db-dao.md)和 ActiveRecord(db-active-record.md)同样适用:

$result = Customer::getDb()->cache(function ($db) { return Customer::find()->where(['id' => 1])->one(); });

自 2.0.14 起,可以使用以下快捷写法:

(new Query())->cache(7200)->all(); // 以及 User::find()->cache(7200)->all();

全局配置项

查询缓存通过yii\db\Connection提供三个全局可配置选项:

配置项默认值说明
enableQueryCachetrue是否开启查询缓存。注意:要真正生效,还需要有queryCache指定的有效缓存组件
queryCacheDuration查询结果在缓存中有效的秒数;设为0表示永久有效。该值是调用cache()而未显式指定时长时的默认值
queryCache'cache'使用的缓存应用组件 ID;只有存在有效的缓存组件时查询缓存才会启用

更多用法

当多个 SQL 查询都想利用查询缓存时,可使用$db->cache()

$duration = 60; // 查询结果缓存 60 秒 $dependency = ...; // 可选依赖 $result = $db->cache(function ($db) { // ... 在这里执行 SQL 查询 ... return $result; }, $duration, $dependency);

匿名函数内的所有 SQL 查询都会按指定时长与依赖被缓存;若某查询结果在缓存中有效,该查询会被跳过、直接返回缓存结果。不传$duration时使用queryCacheDuration的值。

有时需要在大范围缓存内对个别查询禁用查询缓存,可用$db->noCache()

$result = $db->cache(function ($db) { // 使用查询缓存的 SQL 查询 $db->noCache(function ($db) { // 不使用查询缓存的 SQL 查询 }); // ... return $result; });

如果只想对单个查询启用查询缓存,可以在构建命令时调用Command::cache()

// 启用查询缓存,时长 60 秒 $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();

也可以用Command::noCache()对单条命令禁用:

$result = $db->cache(function ($db) { // 使用查询缓存的 SQL 查询 // 这条命令不使用查询缓存 $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne(); // ... return $result; });

查询缓存的限制

查询缓存对包含资源句柄(resource handler)的查询结果无效,例如某些 DBMS 中BLOB列会返回资源句柄。此外,部分缓存存储有大小限制(如 memcache 单条上限 1MB),查询结果超过该上限时缓存会失败。

缓存刷新(Cache Flushing)

需要使全部缓存数据失效时,可调用flush();也可以从控制台执行yii cache/flush。缓存相关的控制台命令如下:

命令作用
yii cache列出应用中可用的缓存组件
yii cache/flush cache1 cache2刷新指定的缓存组件(可传多个组件名,用空格分隔)
yii cache/flush-all刷新应用中的所有缓存组件
yii cache/flush-schema db清除指定连接组件的数据库表结构缓存

提示:控制台应用默认使用独立的配置文件。为达到预期效果,请确保 Web 与控制台应用的配置中注册了相同的缓存组件。

片段缓存(Fragment Caching)

片段缓存用于缓存网页的某个片段。例如页面中的表格展示了年度销售概要,就可以把该表格的生成结果缓存起来,避免每个请求都重新计算。片段缓存构建在数据缓存之上。

基本用法

在视图(structure-views.md)中使用如下语法:

if ($this->beginCache($id)) { // ... 在这里书写要生成的片段内容 ... $this->endCache(); }

即把内容生成逻辑包在yii\base\View::beginCache()yii\base\View::endCache()这对调用之间。若内容已在缓存中命中,beginCache()会直接渲染缓存内容并返回false,从而跳过内容生成逻辑;否则执行生成逻辑,并在endCache()时把生成的内容捕获、存入缓存。与数据缓存类似,需要一个唯一的$id标识缓存片段。

删除某个片段缓存的方式:

Yii::$app->cache->delete(['yii\widgets\FragmentCache', $id]);

缓存选项

通过beginCache()的第二个参数传入选项数组,可对片段缓存进行定制;在内部,这些选项用于配置实现片段缓存功能的yii\widgets\FragmentCache组件。

时长(duration):指定内容在缓存中有效多久。下面的代码把片段最多缓存 1 小时:

if ($this->beginCache($id, ['duration' => 3600])) { // ... 在这里书写要生成的片段内容 ... $this->endCache(); }

未设置该选项时默认值为60,即缓存内容 60 秒后过期。

依赖(dependencies):与数据缓存一样,片段可以携带依赖。例如所展示的帖子内容依赖帖子是否被修改。通过dependency选项传入yii\caching\Dependency对象,或传入用于创建依赖对象的配置数组。下面指定片段依赖updated_at列值的变化:

$dependency = [ 'class' => 'yii\caching\DbDependency', 'sql' => 'SELECT MAX(updated_at) FROM post', ]; if ($this->beginCache($id, ['dependency' => $dependency])) { // ... 在这里书写要生成的片段内容 ... $this->endCache(); }

变体(variations):缓存内容可以随某些参数产生变体。例如多语言应用中,同一段视图代码会按语言生成不同内容,因此缓存也要按当前语言区分。通过variations选项指定,其值为标量组成的数组,每个元素代表一个变体维度:

if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) { // ... 在这里书写要生成的片段内容 ... $this->endCache(); }

开关(enabled):有时只想在满足特定条件时才启用片段缓存。例如包含表单的页面,只希望首次 GET 请求时缓存表单,后续 POST 请求的表单可能包含用户输入,不应缓存。通过enabled选项控制:

if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) { // ... 在这里书写要生成的片段内容 ... $this->endCache(); }

嵌套缓存

片段缓存可以嵌套——被缓存的片段可以放进另一个同样被缓存的片段中。例如内层缓存评论,外层把文章内容连同评论一起缓存。嵌套示例:

if ($this->beginCache($id1)) { // ...内容生成逻辑... if ($this->beginCache($id2, $options2)) { // ...内容生成逻辑... $this->endCache(); } // ...内容生成逻辑... $this->endCache(); }

嵌套缓存可以设置不同的选项。例如内外层可设置不同的时长:外层数据失效时,内层仍有效的片段依然可用;但反过来并非如此——只要外层被判为有效,即使内层已失效,外层仍会继续提供包含旧内容的副本。因此,若嵌套缓存的时长或依赖配置不当,失效的内层数据会残留在外层缓存中,务必谨慎设计。

动态内容(Dynamic Content)

使用片段缓存时常遇到整体较静态、只有一两处例外地动态的情况。例如页面头部同时显示主导航菜单与当前用户名;另一类问题是缓存内容中包含了每次请求都必须执行的 PHP 代码(如注册资源包的代码)。这两类问题都可以通过"动态内容"特性解决。

动态内容指即使包含在片段缓存中也绝不应被缓存的那部分输出。为了让它始终保持动态,即使外层内容来自缓存,每次请求也必须执行相应 PHP 代码来重新生成。在缓存的片段内调用yii\base\View::renderDynamic()即可在目标位置插入动态内容:

if ($this->beginCache($id1)) { // ...内容生成逻辑... echo $this->renderDynamic('return Yii::$app->user->identity->name;'); // ...内容生成逻辑... $this->endCache(); }

renderDynamic()接受一段 PHP 代码作为参数,其返回值即被视为动态内容。无论外层片段是否由缓存提供,这段 PHP 代码都会在每次请求中执行。自 2.0.14 起,动态内容 API 通过yii\base\DynamicContentAwareInterface接口与yii\base\DynamicContentAwareTrait公开,yii\widgets\FragmentCache类即为其实现示例。

页面缓存(Page Caching)

页面缓存在服务器端缓存整个页面的内容,当同一页面再次被请求时直接由缓存返回,而不是从头生成。

页面缓存由yii\filters\PageCache动作过滤器(参见 structure-filters.md)支持,在控制器类中这样使用:

public function behaviors() { return [ [ 'class' => 'yii\filters\PageCache', 'only' => ['index'], 'duration' => 60, 'variations' => [ \Yii::$app->language, ], 'dependency' => [ 'class' => 'yii\caching\DbDependency', 'sql' => 'SELECT COUNT(*) FROM post', ], ], ]; }

上述配置表示:页面缓存仅用于index动作;页面内容最多缓存 60 秒;按当前应用语言产生变体;当帖子总数发生变化时缓存页面失效。

可见页面缓存与片段缓存非常相似——两者都支持durationdependenciesvariationsenabled等选项。主要区别在于实现形态:页面缓存是动作过滤器,片段缓存是组件(widget)。片段缓存和动态内容也都可以与页面缓存组合使用。

HTTP 缓存(HTTP Caching)

除了前文所述的服务器端缓存,Web 应用还可以利用客户端缓存,省去反复生成并发送相同页面内容的时间。

要使用客户端缓存,只需把yii\filters\HttpCache配置为控制器动作的过滤器,使渲染结果可被缓存。HttpCache仅对GETHEAD请求生效,并处理三种缓存相关的 HTTP 头:

属性对应 HTTP 头
lastModifiedLast-Modified
etagSeedETag
cacheControlHeaderCache-Control

Last-Modified

Last-Modified头用时间戳表明页面自客户端缓存以来是否发生变化。配置lastModified属性即可启用发送该头,其值必须是返回页面更新时刻 UNIX 时间戳的 PHP 可调用对象,签名如下:

/** * @param Action $action 当前正在处理的动作对象 * @param array $params "params" 属性的值 * @return int 表示页面更新时刻的 UNIX 时间戳 */ function ($action, $params)

使用示例:

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'); }, ], ]; }

上述代码表示仅在index动作启用 HTTP 缓存,Last-Modified基于帖子最新更新时间生成。浏览器首次访问index页面时,页面在服务器上生成并发送;若浏览器再次访问且期间帖子没有变化,服务器不再重新生成页面,浏览器直接使用客户端缓存的副本——服务器端渲染与页面内容发送都被省去。

ETag

ETag(Entity Tag)是表示页面内容的哈希;页面变化则哈希随之变化。通过比较服务器端生成的哈希与客户端持有的哈希,即可判断页面是否变化、是否需要重发。

配置etagSeed属性即可启用ETag头的发送,其值是一个返回 ETag 哈希种子的 PHP 可调用对象,签名如下:

/** * @param Action $action 当前正在处理的动作对象 * @param array $params "params" 属性的值 * @return string 用作生成 ETag 哈希种子的字符串 */ function ($action, $params)

使用示例:

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]); }, ], ]; }

上述代码表示仅在view动作启用 HTTP 缓存,ETag基于请求帖子的标题与内容生成。浏览器首次访问view页面时页面在服务器上生成并发送;若再次访问且帖子标题、内容没有变化,服务器不再重新生成页面,浏览器直接使用缓存副本。

ETag 相比Last-Modified支持更复杂、更精确的缓存策略,例如站点切换主题时让 ETag 失效。但 ETag 每次请求都要重新计算,若生成方法开销过大,反而会损害HttpCache的本意、引入不必要的开销——请尽量用简单的表达式来判定页面内容是否变化。

注意:依据 RFC 7232,当ETagLast-Modified同时设置时,HttpCache会同时发送两者;若客户端同时发送If-None-MatchIf-Modified-Since头,则只尊重前者。

Cache-Control

Cache-Control头声明页面通用的缓存策略,通过cacheControlHeader属性设置头值即可发送。默认发送的头为:

Cache-Control: public, max-age=3600

会话缓存限制器(Session Cache Limiter)

当页面使用会话时,PHP 会自动发送一些与缓存相关的 HTTP 头(由 PHP 配置文件中的session.cache_limiter决定),这些头可能干扰或禁用HttpCache期望实现的缓存功能。为避免该问题,HttpCache默认会自动禁用这些头的发送;如需改变此行为,可设置sessionCacheLimiter属性,其取值可为publicprivateprivate_no_expirenocache等字符串(含义参见 PHP 的session_cache_limiter()函数文档)。

对 SEO 的影响

搜索引擎的爬虫倾向于遵循缓存头。部分爬虫对一定时间内单域名的处理页数有限制,因此引入缓存头、减少需要处理的页面数量,可能有助于加快站点索引的建立。

小结

Yii2 的缓存体系呈清晰的层次结构:底层的数据缓存提供统一的缓存组件抽象与多种存储后端,查询缓存在数据缓存之上缓存 SQL 结果;视图层的片段缓存缓存页面局部并可嵌套、可注入动态内容;过滤器层的页面缓存缓存整个页面;而 HTTP 缓存则把缓存延伸到浏览器端。理解并善用这四层机制,配合 framework/caching 中Cache基类的统一 API(键前缀、序列化、过期、依赖),即可在几乎不改动业务逻辑的前提下,从服务器到客户端全方位提升应用性能。

  • 后端
  • Web框架

【免费下载链接】yii2

Yii 2: The Fast, Secure and Professional PHP Framework

项目地址:https://gitcode.com/gh_mirrors/yi/yii2
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 3:06:16

徐春明拆解源码:3个坑点搞定面试必问难题

徐春明拆解源码:3个坑点搞定面试必问难题 看了一堆教程还是不会写项目?别慌,这很正常。 很多开发者盯着文档看,脑子懂了,手却没动过。等到面试官甩出 面试必问 的底层原理题,立马卡壳。 今天咱们不背八股文,直接上手。 我以 徐春明 在开源社区分享的经典并发案例为蓝本,带你拆解一段真实的生产级代码。…

作者头像 李华
网站建设 2026/9/23 3:06:04

前端面试突击:形状补间动画保姆级教程

前端面试突击:形状补间动画保姆级教程 版本升级后 API 全变了?别慌,很多开发者在复习前端基础时,发现 Flash 时代的形状补间概念在 CSS 和 Canvas 中早已重构。这篇保姆级教程,带你彻底搞懂形状补间动画的核心逻辑。 考点梳理:什么是形状补间动画…

作者头像 李华
网站建设 2026/9/23 3:05:56

3天搞定集训总结系统:从代码到部署的保姆级教程

3天搞定集训总结系统:从代码到部署的保姆级教程 刚学完Python或Java,看着语法书点头如捣蒜,真让你搭个“集训总结”系统,脑子瞬间一片空白。这种“语法熟、项目懵”的断层,是90%初学者最大的痛点。今天这篇 保姆级教程…

作者头像 李华
网站建设 2026/9/23 3:05:48

为什么我的网页打不开:5步源码解析定位网络断点

为什么我的网页打不开:5步源码解析定位网络断点 官方文档翻了三遍,还是没找到为什么我的网页打不开的根本原因?这种时候,光看现象没用,得直接钻进底层逻辑里看。很多转岗做后端的同事,习惯看 API 文档,却忽略了浏览器发起请求时的“黑盒”过程。今天不讲虚的,我们直接通过 源码解析 ,拆解浏览器从输入…

作者头像 李华
网站建设 2026/9/23 3:05:32

搞懂一个羽一个佳,别再让配置环境卡住你的实战项目

搞懂一个羽一个佳,别再让配置环境卡住你的实战项目 配置环境就卡半天,这是多少开发者的噩梦?特别是当你急着跑通一个 实战项目 ,结果卡在依赖解析、版本冲突或者路径错误上,那种抓狂感谁懂。很多兄弟以为这是工具链的问题,其实是你对底层机制理解不够。今天咱们不聊虚的,直接拆解一个高频出现的“伪”报错,顺便聊…

作者头像 李华
网站建设 2026/9/23 3:05:30

安全生产管理台账面试避坑指南附完整示例

安全生产管理台账面试避坑指南附完整示例 面试官问“安全生产管理台账”时,你答不上来原理?别慌。很多人以为这是行政填表,其实它是合规审计的核心证据链。今天拆解这个高频考点,直接给出一套可落地的完整示例,帮你把“填表”变成“系统思维”。 考点梳理:从纸质表格到数字化闭环…

作者头像 李华