Laravel 8及以上版本中传递请求至异常处理并捕获404请求源URL的最佳实现方案
Laravel 8及以上版本中传递请求至异常处理并捕获404请求源URL的最佳实现方案
嘿,这个需求我刚好处理过好多次,Laravel 8及以上版本里其实有非常简洁的实现方式,完全不用复杂的配置就能搞定——因为Laravel的异常处理流程天生就能访问当前请求,你根本不需要手动“传递”请求到异常里,直接拿就行!
1. 核心实现:在异常处理器中捕获404请求信息
首先打开项目根目录下的app/Exceptions/Handler.php,我们要在report方法里针对404异常做专门处理。这个方法负责记录异常日志,刚好适合我们收集请求URL、用户代理(用来判断是不是机器人)、IP这些关键信息。
修改后的report方法示例:
public function report(Throwable $exception) { // 专门捕获404异常 if ($exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) { // 获取请求的完整URL(包含查询参数) $requestUrl = request()->fullUrl(); // 获取用户代理,用来识别爬虫/机器人 $userAgent = request()->header('User-Agent'); // 获取请求IP $ipAddress = request()->ip(); // 方式一:单独记录一条清晰的404日志 logger()->error('404 页面访问记录', [ '访问URL' => $requestUrl, '用户代理' => $userAgent, '访问IP' => $ipAddress, '时间' => now()->toDateTimeString() ]); // 方式二:把信息附加到默认的异常日志上下文里 parent::report($exception->withContext([ 'request_url' => $requestUrl, 'user_agent' => $userAgent, 'ip' => $ipAddress ])); return; } // 其他异常按默认逻辑处理 parent::report($exception); }
2. 可选:在自定义404页面展示请求URL
如果你想在自己的404页面上告诉用户“你访问的XX页面不存在”,可以在render方法里把请求URL传递到视图:
public function render($request, Throwable $exception) { if ($exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) { // 把请求URL传给自定义404视图 return response()->view('errors.404', [ 'requestedUrl' => $request->fullUrl() ], 404); } return parent::render($request, $exception); }
之后在resources/views/errors/404.blade.php里就可以直接用{{ $requestedUrl }}来显示用户访问的不存在的URL了。
3. 进阶:快速区分真人与机器人
要判断访问404的是真人还是机器人,最直接的方式是解析用户代理(User-Agent)。Laravel自带了agent()辅助函数,可以帮你快速识别:
// 在report方法的404处理逻辑里添加 $isRobot = agent()->isRobot(); // 然后把这个字段也加入日志或数据库 logger()->error('404 页面访问记录', [ // ...其他字段 '是否为机器人' => $isRobot ? '是' : '否' ]);
不过要注意,有些恶意机器人会伪装成普通浏览器的UA,如果你需要更精准的识别,可以结合IP黑名单或者专业的爬虫识别库,但大部分场景下agent()->isRobot()足够用了。
4. 进阶:将404记录存入数据库
如果想长期统计分析404请求,可以创建一个专门的模型来存储这些记录:
- 先创建迁移文件:
php artisan make:migration create_not_found_logs_table
- 在迁移文件里添加字段:
public function up() { Schema::create('not_found_logs', function (Blueprint $table) { $table->id(); $table->text('url'); $table->text('user_agent')->nullable(); $table->string('ip')->nullable(); $table->boolean('is_robot')->default(false); $table->timestamps(); }); }
- 创建对应的模型
app/Models/NotFoundLog.php,然后在Handler的report方法里添加存储逻辑:
\App\Models\NotFoundLog::create([ 'url' => $requestUrl, 'user_agent' => $userAgent, 'ip' => $ipAddress, 'is_robot' => agent()->isRobot() ]);
这样你就能随时通过数据库查询哪些URL被频繁访问(不管是真人误点还是机器人爬取),方便后续优化路由或者屏蔽恶意爬虫。
备注:内容来源于stack exchange,提问作者Hashim Aziz
相关产品推荐
相关产品推荐

