Laravel使用Cache缓存查询时firstOrFail未返回404如何解决
问题原因
该问题确实和Cache::remember的执行逻辑直接相关,同时存在一个容易忽略的笔误:
- 缓存写入逻辑漏洞:当传入不存在的slug时,如果某次请求没有触发
firstOrFail()的异常(比如异常被全局捕获后返回了null),Cache::remember会把这个null值作为正常结果写入缓存,后续相同slug的请求会直接读取缓存中的null,根本不会执行闭包内的数据库查询和firstOrFail()逻辑,自然不会返回404。 - 变量名传递错误:控制器中向视图传递的变量名是
country,你在Blade中使用的是$post,变量名不匹配本身也会抛出变量不存在的错误。
修复步骤
- 第一步:对齐视图变量名
修正控制器的传参键名,和视图内调用的变量名保持一致:
public function single($slug) { return view('post.single', [ 'post' => $this->getPostBySlugCached($slug), ]); }
- 第二步:调整缓存查询逻辑,禁止缓存空结果
修改缓存方法,数据库查询时先取结果,查不到就直接抛出404,不把null写入缓存:
private function getPostBySlugCached(string $slug) { return Cache::tags(['post'])->remember('post:slug:'.$slug, CacheRemember::FOUR_WEEKS, function () use ($slug) { $post = Post::where('slug', $slug)->first(); // 不存在直接中断返回404,不会走到缓存写入流程 if (!$post) { abort(404); } return $post; }); }
注意:如果之前错误逻辑已经把空值写入缓存,先执行
Cache::tags(['post'])->flush();清空该标签下的所有缓存,再验证效果。
- 可选加固:统一配置模型缺失异常的响应逻辑
如果想继续使用firstOrFail()写法,可以在全局异常处理中明确配置ModelNotFoundException的返回规则,避免异常被其他逻辑拦截返回null:
打开app/Exceptions/Handler.php,在register方法中添加如下配置:
use Illuminate\Database\Eloquent\ModelNotFoundException; $this->renderable(function (ModelNotFoundException $e, $request) { abort(404); });
内容的提问来源于stack exchange,提问作者eskimo
相关产品推荐
相关产品推荐

