如何将所有404请求记录到数据库?Laravel实现疑问
嘿,这个需求其实Laravel已经有很方便的解决方案啦!我来一步步给你捋清楚怎么实现,顺便优化下你现有的代码~
方案一:用路由Fallback(最简单直接)
Laravel提供了fallback路由,专门用来处理所有未匹配到其他路由的请求——也就是我们常说的404场景,完全不用折腾中间件或者服务提供者,几步就能搞定:
1. 优化你的控制器方法
你原来的代码可以简化很多,用Laravel的updateOrCreate方法就能一键完成“存在则计数+1,不存在则新增”的逻辑,而且原来的empty(MissingPage::where('slug', $slug)->get())写法不太靠谱(因为get()返回的是集合,即使为空也不是严格的empty),改成下面这样更高效:
use Illuminate\Http\Request; use App\Models\MissingPage; use Illuminate\Support\Facades\DB; public function test(Request $request) { // 获取当前请求的路径,比如访问example.com/demo的话,这里拿到的就是"demo" $slug = $request->path(); // 如果你只想记录路径的第一部分(比如example.com/demo/subpage只记录"demo"),可以改成: // $slug = explode('/', $request->path())[0]; // 一键完成新增/更新操作 MissingPage::updateOrCreate( ['slug' => $slug], // 匹配条件:slug等于当前请求的路径 ['count' => DB::raw('count + 1')] // 如果存在,count字段加1;如果不存在,默认count为1(需要在模型里设置默认值,或者改成['count' => 1]) ); // 最后一定要返回404响应,让Laravel显示你自定义的404页面 abort(404); }
2. 在web.php里配置Fallback路由
只需要在路由文件的末尾加上这一行(一定要放在所有其他路由的后面,因为路由是按顺序匹配的):
use App\Http\Controllers\MissingPageController; Route::fallback([MissingPageController::class, 'test']);
这样一来,所有没被其他路由匹配到的请求,都会自动走到这个test方法里完成记录,然后返回404页面,完美!
方案二:用全局中间件(适合全场景捕获404)
如果你的应用既有web端又有API端,或者需要更全局的404捕获,那用中间件会更灵活:
1. 创建中间件
先执行Artisan命令生成中间件:
php artisan make:middleware RecordMissingPage
2. 编写中间件逻辑
打开app/Http/Middleware/RecordMissingPage.php,修改handle方法:
use Illuminate\Http\Request; use App\Models\MissingPage; use Illuminate\Support\Facades\DB; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; public function handle(Request $request, Closure $next) { try { $response = $next($request); // 检查响应状态码是否是404 if ($response->getStatusCode() === 404) { $this->recordMissingPage($request); } return $response; } catch (NotFoundHttpException $e) { // 捕获代码里主动抛出的404异常(比如abort(404)) $this->recordMissingPage($request); // 继续抛出异常,让Laravel处理404页面 throw $e; } } // 抽离成单独的方法,更清晰 private function recordMissingPage(Request $request) { $slug = $request->path(); // 可以在这里排除静态资源(比如css、js、图片),避免无效记录 $excludedExtensions = ['css', 'js', 'png', 'jpg', 'svg', 'ico']; $extension = pathinfo($slug, PATHINFO_EXTENSION); if (in_array($extension, $excludedExtensions)) { return; } MissingPage::updateOrCreate( ['slug' => $slug], ['count' => DB::raw('count + 1')] ); }
3. 注册中间件
打开app/Http/Kernel.php,把这个中间件加到web中间件组里(如果需要API也生效,就加到api组):
protected $middlewareGroups = [ 'web' => [ // ... 其他已有的中间件 \App\Http\Middleware\RecordMissingPage::class, ], ];
额外提醒
- 记得给
missing_pages表的slug字段加唯一索引,这样updateOrCreate能准确匹配,避免重复数据; - 如果你的
count字段默认值不是1,记得在模型里设置$attributes = ['count' => 1];,或者在updateOrCreate的第二个参数里写['count' => 1]; - 如果不想记录某些特定路径,可以在方法里加判断过滤掉。
内容的提问来源于stack exchange,提问作者Ali Özen
相关产品推荐
相关产品推荐

