ThinkPHP 5.1 的 cache() 方法仅缓存控制器返回数据,不缓存响应头、状态码及 Cookie;TP6 移除该方法,改用中间件驱动的响应缓存,键名规则、作用域和缓存控制均不兼容 TP5.1,升级需清空旧缓存并显式配置。

ThinkPHP 5.1 的 cache 方法不缓存请求响应体
很多人以为调用 $this->cache(3600) 就能缓存整个 HTTP 响应,其实它只缓存控制器返回的数据(即 return 的数组或对象),不介入 Response 输出流程。缓存键由路由 + 请求参数生成,但 Response 的状态码、Header、Content-Type 等全被忽略。
常见错误现象:200 响应被缓存了,但后续请求返回 500 错误时仍从缓存读出旧数据;或者接口返回了 Set-Cookie,缓存后下次直接复用导致会话错乱。
- 仅适用于纯数据接口(如 JSON API),且必须确保业务逻辑幂等
- 缓存有效期单位是秒,但实际是否生效还取决于
cache.driver配置(如file驱动在 CLI 下可能失效) - 若开启
app_debug = true,该缓存自动禁用,调试时容易误判缓存未生效
ThinkPHP 6.x 移除了控制器层的 cache() 方法
TP6 彻底删掉了控制器中 $this->cache() 这个快捷方法,官方转向中间件驱动的响应缓存机制。这不是“功能降级”,而是把缓存决策从控制器代码里剥离出来,交由更可控的生命周期节点处理。
使用场景变了:你不能再在某个 index() 方法里写一行 $this->cache(600) 就完事;必须显式注册中间件,并配置缓存策略(比如按 URL 规则、Header 条件或响应状态码过滤)。
立即学习“PHP免费学习笔记(深入)”;
- 核心中间件是
think\middleware\CacheMiddleware,需在app/middleware.php或路由定义中启用 - 缓存键默认包含
Request::url()+Request::method()+Request::header('accept'),对 RESTful 接口更友好 - TP6 默认不缓存带 Cookie 或 Authorization Header 的请求,避免敏感信息泄漏,这点和 TP5.1 完全不同
TP5.1 升级到 TP6 时最常踩的坑:缓存键不兼容
TP5.1 的缓存键生成逻辑硬编码在 think\Controller 里,格式类似 route|/api/user?id=123;而 TP6 的 CacheMiddleware 使用 md5($request->url() . $request->method()),两者完全无法复用。升级后旧缓存全部失效,但不会报错,容易误以为“缓存没起作用”。
更麻烦的是:如果项目混用了 TP5.1 的手动缓存(Cache::tag()->set())和 TP6 的响应缓存,Redis 里会同时存在两套键名规则,清理困难。
- 升级前务必清空原有缓存存储(尤其是 Redis 或 Memcached)
- 不要试图复用 TP5.1 的缓存配置项(如
cache.prefix),TP6 已改用cache.default和cache.stores.[driver].prefix - TP6 的缓存中间件默认跳过 POST/PUT/DELETE 请求,若需缓存这类请求,必须自定义中间件并重写
shouldCache()方法
响应缓存是否启用,得看 Response 对象是否被标记为可缓存
无论 TP5.1 还是 TP6,最终能否真正写入缓存,取决于 Response 实例是否满足「可缓存」条件。TP5.1 是隐式判断(只看控制器返回值类型),TP6 是显式控制(通过 Response::withCacheControl() 或中间件配置)。
一个典型疏漏:用 json(['code'=>0]) 返回数据时,TP6 默认给响应加上 Cache-Control: private, must-revalidate,而多数 CDN 或反向代理会拒绝缓存 private 响应——结果就是你以为开了缓存,实际上流量全打到了 PHP 进程。
- 对外公开接口务必调用
response()->withCacheControl('public, max-age=3600') - TP6 中
Response::cache()是快捷方法,但底层仍依赖中间件注册,单独调用无效 - 如果用了 Swoole 或 RoadRunner,注意缓存驱动是否支持长连接下的并发写入(如
file驱动在多进程下有锁竞争风险)



















