本文目录导读:

在Laravel中,使用中间件记录请求和响应日志是一个很常见的需求,以下是几种实现方式:
创建自定义中间件(推荐)
创建中间件
php artisan make:middleware RequestResponseLogger
编写中间件逻辑
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
class RequestResponseLogger
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
// 记录请求日志
$this->logRequest($request);
// 继续处理请求
$response = $next($request);
// 记录响应日志
$this->logResponse($request, $response);
return $response;
}
/**
* 记录请求日志
*/
protected function logRequest(Request $request)
{
Log::channel('api')->info('Request', [
'method' => $request->method(),
'url' => $request->fullUrl(),
'headers' => $request->headers->all(),
'body' => $request->all(),
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
]);
}
/**
* 记录响应日志
*/
protected function logResponse(Request $request, Response $response)
{
Log::channel('api')->info('Response', [
'url' => $request->fullUrl(),
'status' => $response->getStatusCode(),
'headers' => $response->headers->all(),
'body' => $response->getContent(),
]);
}
}
创建日志频道(可选)
在 config/logging.php 中添加:
'channels' => [
// ... 其他频道
'api' => [
'driver' => 'daily',
'path' => storage_path('logs/api.log'),
'level' => 'info',
'days' => 14,
'formatter' => Monolog\Formatter\LineFormatter::class,
'formatter_with' => [
'format' => "[%datetime%] %channel%.%level_name%: %message% %context%\n",
],
],
],
注册中间件
在 app/Http/Kernel.php 中注册:
全局中间件(所有请求):
protected $middleware = [
// ...
\App\Http\Middleware\RequestResponseLogger::class,
];
路由组中间件:
protected $middlewareGroups = [
'web' => [
// ...
],
'api' => [
// ...
\App\Http\Middleware\RequestResponseLogger::class,
],
];
单个路由中间件:
protected $routeMiddleware = [
// ...
'log.api' => \App\Http\Middleware\RequestResponseLogger::class,
];
使用Terminable中间件(异步日志)
如果希望在响应发送后记录日志,可以使用Terminable中间件:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class AsyncRequestLogger
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
// 保存请求数据以便后续使用
$request->attributes->set('start_time', microtime(true));
return $next($request);
}
/**
* Handle tasks after the response has been sent to the browser.
*/
public function terminate(Request $request, $response)
{
$duration = microtime(true) - $request->attributes->get('start_time', 0);
Log::channel('api')->info('API Request Log', [
'method' => $request->method(),
'url' => $request->fullUrl(),
'status' => $response->getStatusCode(),
'duration' => round($duration * 1000, 2) . 'ms',
'ip' => $request->ip(),
]);
}
}
记录敏感信息过滤
在实际应用中,可能需要过滤敏感信息(如密码、token等):
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class SecureRequestLogger
{
protected $hiddenFields = [
'password',
'password_confirmation',
'token',
'secret',
'credit_card',
];
public function handle(Request $request, Closure $next)
{
$requestData = $this->filterSensitiveData($request->all());
Log::info('Request', [
'method' => $request->method(),
'url' => $request->fullUrl(),
'body' => $requestData,
]);
$response = $next($request);
Log::info('Response', [
'url' => $request->fullUrl(),
'status' => $response->getStatusCode(),
]);
return $response;
}
protected function filterSensitiveData(array $data)
{
foreach ($this->hiddenFields as $field) {
if (isset($data[$field])) {
$data[$field] = '*** FILTERED ***';
}
}
return $data;
}
}
使用事件监听器(高级用法)
也可以使用Laravel的事件系统来实现:
// app/Providers/EventServiceProvider.php
protected $listen = [
\Illuminate\Foundation\Http\Events\RequestHandled::class => [
\App\Listeners\LogRequestResponse::class,
],
];
创建监听器:
php artisan make:listener LogRequestResponse
<?php
namespace App\Listeners;
use Illuminate\Foundation\Http\Events\RequestHandled;
use Illuminate\Support\Facades\Log;
class LogRequestResponse
{
public function handle(RequestHandled $event)
{
$request = $event->request;
$response = $event->response;
Log::info('Request handled', [
'method' => $request->method(),
'url' => $request->fullUrl(),
'status' => $response->getStatusCode(),
'duration' => microtime(true) - LARAVEL_START,
]);
}
}
使用建议
- 性能考虑:生产环境中建议使用异步日志记录
- 日志级别:根据不同环境设置不同的日志级别
- 敏感信息:确保过滤掉密码、token等敏感信息
- 日志轮转:使用
daily驱动自动管理日志文件大小 - 条件记录:可以根据需求只记录特定状态码或错误的请求
// 条件记录示例
if ($response->getStatusCode() >= 400) {
Log::warning('Error response', [...]);
}
选择哪种方式取决于你的具体需求,一般推荐使用方法一(自定义中间件),因为它最灵活且易于维护。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播