有时候难免要对 Http 的请求和响应包体进行记录以方便查找问题或做什么。
Laravel 的 Http 客户端是基于 Guzzle 进行封装的,在上层进行了简化,并没有直接给我们留相关的日志配置,想要对请求的 http 进行详细的记录,则需要借助于 Guzzle 的 Handler/中间件,和 withOptions 方法。
首先们要使用 composer 安装一个第三方的 Guzzle 日志中间件。
composer require rtheunissen/guzzle-log-middleware
该中间件比较简单,仅是在请求发生时将请求和响应对象传递给我们指定的闭包,然后我们在闭包中直接调用 Log 的方法进行记录即可。
简单的演示如下:
$stack = new HandlerStack();
$stack->setHandler(new CurlHandler()); //使用 HandlerStack 后必须指定一个 Handler
//日志中间件
$logger = new Logger(function ($level, $message, array $context) {
Log::log($level, $message);
});
$stack->push($logger);
$res = Http::withOptions([
'handler' => $stack
])->post($url, $data);
此时请求发生时我们就会在日志里看到一条这样的简单日志:
[2021-04-28 17:00:30] local.INFO: homestead GuzzleHttp/7 - [28/Apr/2021:17:00:30 +0800] "POST /your/request/url HTTP/1.1" 200 136
不过显示这个日志太简单了,我们需要更详细的信息,比如请求和响应的头信息及主体内容,通过该中间件的主页得知可使用一个闭包来进行 message 的格式化。
于是我们对 Logger 进行一番修改,从 Request 和 Response 中取出相应的信息,并且拼装成 Http 的包体结构,结果如下:
$logger = new Logger(function ($level, $message, array $context) {
Log::log($level, $message);
}, function ($request, $response, $reason) {
/**
* @var Request $request
* @var Response $response
*/
$requestBody = $request->getBody();
$requestBody->rewind();
//请求头
$requestHeaders = [];
foreach ($request->getHeaders() as $k => $vs) {
foreach ($vs as $v) {
$requestHeaders[] = "$k: $v";
}
}
//响应头
$responseHeaders = [];
foreach ($response->getHeaders() as $k => $vs) {
foreach ($vs as $v) {
$responseHeaders[] = "$k: $v";
}
}
$uri = $request->getUri();
$path = $uri->getPath();
if ($query = $uri->getQuery()) {
$path .= '?'.$query;
}
return sprintf(
"Request %s\n%s %s HTTP/%s\r\n%s\r\n\r\n%s\r\n--------------------\r\nHTTP/%s %s %s\r\n%s\r\n\r\n%s",
$uri,
$request->getMethod(),
$path,
$request->getProtocolVersion(),
join("\r\n", $requestHeaders),
$requestBody->getContents(),
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase(),
join("\r\n", $responseHeaders),
$response->getBody()->getContents()
);
});
发送请求后,日志内容如下:
[2021-04-28 17:06:11] local.NOTICE: Request https://www.baidu.com/
POST / HTTP/1.1
User-Agent: GuzzleHttp/7
Content-Type: application/json
Host: www.baidu.com
{"hello":"I am a fake POST."}
--------------------
HTTP/1.1 302 Found
Bdpagetype: 3
Connection: keep-alive
Content-Length: 154
Content-Type: text/html
Date: Wed, 28 Apr 2021 09:06:11 GMT
Location: https://www.baidu.com/search/error.html
Server: BWS/1.1
Set-Cookie: BDSVRTM=0; path=/
Traceid: 161960077103724047468432068516915727024
X-Ua-Compatible: IE=Edge,chrome=1
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
怎么样,详细否?