Laravel 7 中间件缓存无法命中:始终返回X-Proxy-Cache: MISS
解决Laravel 7中间件缓存中
Cache::has()始终返回false的问题 根据你描述的情况——缓存文件确实存在但Cache::has($key)返回false,且执行dd()时缓存文件被自动删除,我梳理了几个最可能的原因及对应的解决方案:
1. 缓存已过期,Laravel自动清理过期条目
你在路由中设置的缓存TTL是5(即5分钟),如果测试时缓存已经超过有效期,Laravel的文件缓存驱动会自动判定缓存失效,返回false并删除过期的缓存文件。
解决方案:
- 临时将TTL改大(比如
cacheable:1440,即24小时),重新生成缓存后立即测试,确认是否是过期问题。 - 查看缓存文件的内容,Laravel的文件缓存会在内容开头存储过期时间戳,你可以通过这个判断缓存是否还在有效期内。
2. 缓存内容格式不匹配,反序列化失败
你提到打开缓存文件能看到目标页面内容,但根据你的代码,存储的是数组['content' => $response->content()],正常情况下Laravel会对这个数组进行PHP序列化,缓存文件内容应该是类似a:1:{s:7:"content";s:XXX:"页面HTML内容";}的格式,而非纯HTML。
如果缓存文件是纯HTML,说明这是旧缓存(比如你之前的代码直接存储响应字符串而非数组),当Laravel尝试反序列化纯HTML时会失败,进而删除该缓存文件并返回false。
解决方案:
- 删除
storage/framework/cache/data目录下的所有缓存文件,清空旧缓存后重新生成。 - 可以简化缓存逻辑,直接存储响应字符串而非数组,避免序列化/反序列化问题:
// 修改存储逻辑 if(!empty($response->content())) Cache::put($key, $response->content(), $ttl); // 修改读取逻辑 if(Cache::has($key)){ $cache = Cache::get($key); $response = response($cache); $response->header('X-Proxy-Cache', 'HIT'); }
3. 缓存键生成不一致
虽然你用了相同的逻辑生成缓存键,但可能存在请求参数处理的细微差异(比如某些参数的大小写、空值处理),导致存储和读取时的$key不一致。
解决方案:
- 在中间件中添加日志输出,确认存储和读取时的缓存键完全相同:
use Illuminate\Support\Facades\Log; // 生成key后添加日志 $key = md5(url()->current().'?'.http_build_query($params)); Log::info('当前缓存键: ' . $key); - 查看
storage/logs/laravel.log,对比缓存存储和读取时的键是否一致。
4. 缓存驱动配置异常
检查config/cache.php的配置,确保:
default选项设置为file(你当前用的是文件缓存)stores.file.path指向正确的路径:storage/framework/cache/dataprefix配置没有特殊字符或冲突(不过你用md5生成key,冲突概率极低)
5. 调试缓存文件的实际路径
可以直接验证Laravel是否能找到对应的缓存文件,添加以下代码到中间件中:
use Illuminate\Cache\FileStore; use Illuminate\Filesystem\Filesystem; // ... $key = md5(url()->current().'?'.http_build_query($params)); // 获取Laravel实际查找的缓存文件路径 $store = new FileStore(new Filesystem(), storage_path('framework/cache/data')); $cacheFilePath = $store->path($key); Log::info('缓存文件路径: ' . $cacheFilePath); Log::info('文件是否存在: ' . file_exists($cacheFilePath));
如果文件存在但Cache::has($key)返回false,基本可以确定是反序列化或过期时间的问题。
内容的提问来源于stack exchange,提问作者AlexB
相关产品推荐
相关产品推荐

