- 后端
- Web框架
【免费下载链接】yii2
Yii 2: The Fast, Secure and Professional PHP Framework
缓存是 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\FragmentCache | caching-fragment.md |
| 页面缓存(Page Caching) | 整个页面 | yii\filters\PageCache动作过滤器 | caching-page.md |
| HTTP 缓存(HTTP Caching) | 浏览器端内容 | yii\filters\HttpCache动作过滤器 | caching-http.md |
从源码目录看,Yii2 在 framework/caching 下集中实现了统一的缓存抽象:基类Cache实现了CacheInterface,并为ApcCache、ArrayCache、DbCache、DummyCache、FileCache、MemCache、WinCache等不同存储后端预留了getValue()、setValue()、addValue()、deleteValue()、flushValues()五个抽象方法;依赖体系则由Dependency基类与ChainedDependency、DbDependency、DbQueryDependency、ExpressionDependency、CallbackDependency、FileDependency、TagDependency构成。
数据缓存(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\ApcCache | PHP APC/APCu 扩展 | 集中式胖应用(单服务器、无独立负载均衡)场景下可视为最快选择 |
yii\caching\DbCache | 数据库表 | 必须按DbCache::cacheTable的约定创建缓存表 |
yii\caching\ArrayCache | 进程内数组 | 仅在当前请求内有效;将serializer设为false可进一步提升性能 |
yii\caching\DummyCache | 无(占位) | 不做真实缓存;便于统一代码写法,开发期或后端无缓存时使用,切换后端时无需改业务代码 |
yii\caching\FileCache | 标准文件 | 特别适合缓存大块数据,如页面内容 |
yii\caching\MemCache | memcache/memcached 扩展 | 分布式应用(多服务器、负载均衡)场景下可视为最快选择 |
yii\redis\Cache | Redis 键值存储 | 需要 Redis 2.6.12 及以上版本(该扩展类在独立的 redis 扩展包中) |
yii\caching\WinCache | PHP 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()返回false而exists()返回true的情况。警告:缓存值通过 PHP 原生
serialize()/unserialize()存储和读取(含所附的Dependency对象)。应把缓存后端视为可信存储,绝不能让不可信方写入缓存——反序列化构造的恶意字节可能实例化任意对象,详见 security-best-practices.md 中关于避免不安全反序列化的说明。
查询缓存(Query Caching)
查询缓存是构建在数据缓存之上的一种特殊缓存,专门用于缓存数据库查询结果。
查询缓存需要满足两个前提:一个yii\db\Connection数据库连接,以及一个有效的cache应用组件。基本用法如下,假设$db是yii\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提供三个全局可配置选项:
| 配置项 | 默认值 | 说明 |
|---|---|---|
enableQueryCache | true | 是否开启查询缓存。注意:要真正生效,还需要有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 秒;按当前应用语言产生变体;当帖子总数发生变化时缓存页面失效。
可见页面缓存与片段缓存非常相似——两者都支持duration、dependencies、variations、enabled等选项。主要区别在于实现形态:页面缓存是动作过滤器,片段缓存是组件(widget)。片段缓存和动态内容也都可以与页面缓存组合使用。
HTTP 缓存(HTTP Caching)
除了前文所述的服务器端缓存,Web 应用还可以利用客户端缓存,省去反复生成并发送相同页面内容的时间。
要使用客户端缓存,只需把yii\filters\HttpCache配置为控制器动作的过滤器,使渲染结果可被缓存。HttpCache仅对GET与HEAD请求生效,并处理三种缓存相关的 HTTP 头:
| 属性 | 对应 HTTP 头 |
|---|---|
lastModified | Last-Modified |
etagSeed | ETag |
cacheControlHeader | Cache-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,当
ETag与Last-Modified同时设置时,HttpCache会同时发送两者;若客户端同时发送If-None-Match与If-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属性,其取值可为public、private、private_no_expire、nocache等字符串(含义参见 PHP 的session_cache_limiter()函数文档)。
对 SEO 的影响
搜索引擎的爬虫倾向于遵循缓存头。部分爬虫对一定时间内单域名的处理页数有限制,因此引入缓存头、减少需要处理的页面数量,可能有助于加快站点索引的建立。
小结
Yii2 的缓存体系呈清晰的层次结构:底层的数据缓存提供统一的缓存组件抽象与多种存储后端,查询缓存在数据缓存之上缓存 SQL 结果;视图层的片段缓存缓存页面局部并可嵌套、可注入动态内容;过滤器层的页面缓存缓存整个页面;而 HTTP 缓存则把缓存延伸到浏览器端。理解并善用这四层机制,配合 framework/caching 中Cache基类的统一 API(键前缀、序列化、过期、依赖),即可在几乎不改动业务逻辑的前提下,从服务器到客户端全方位提升应用性能。
- 后端
- Web框架
【免费下载链接】yii2
Yii 2: The Fast, Secure and Professional PHP Framework
相关推荐
Yii 2 缓存机制全指南:数据缓存、片段缓存、页面缓存与 HTTP 缓存
Yii 2 缓存机制全指南:数据缓存、片段缓存、页面缓存与 HTTP 缓存 缓存是 Web 应用提升性能最廉价也最有效的手段之一:把相对静态的数据存入缓存,在请
后端Web框架Yii 2 缓存全攻略:从数据缓存、片段缓存到页面缓存与 HTTP 缓存的完整实践指南
Yii 2 缓存全攻略:从数据缓存、片段缓存到页面缓存与 HTTP 缓存的完整实践指南 缓存是提升 Web 应用性能最廉价、最有效的手段之一。本文基于 Yii
后端Web框架Spring Modulith 运行时观察:监控模块化应用的性能指标
Spring Modulith 运行时观察:监控模块化应用的性能指标 Spring Modulith 是一款基于 Spring Boot 的模块化应用开发框架,
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考