如何为Guzzle的CurlMultiHandler记录请求并获取有效响应?
解决Guzzle CurlMultiHandler日志中$context['response']无效及cURL编码错误问题
问题说明
使用Guzzle的CurlHandler时,日志回调的$context数组能获取完整的请求和响应详情,但切换为CurlMultiHandler后,$context['response']失效,同时出现cURL error 61错误:无法识别内容编码类型,libcurl仅支持deflate、gzip编码。
解决方案
1. 修复cURL编码错误(根源问题)
该错误是因为服务器返回了libcurl不支持的内容编码(如br),或客户端请求了不支持的编码。解决方式如下:
- 主动指定请求仅接受libcurl支持的编码
- 让Guzzle接管响应解码,而非依赖cURL
代码示例:
$client = new Client([ 'handler' => $stack, 'headers' => [ 'Accept-Encoding' => 'gzip, deflate' // 明确请求支持的编码 ], 'decode_content' => true // 由Guzzle自动处理响应解码 ]);
2. 调整日志中间件,确保捕获有效响应
CurlMultiHandler为异步处理,需确保日志中间件能正确捕获Promise状态下的响应:
方式一:使用Guzzle自带的标准化日志中间件
借助MessageFormatter统一格式化请求响应内容,避免手动处理$context:
use GuzzleHttp\Middleware; use GuzzleHttp\MessageFormatter; // 自定义日志格式,可按需调整字段 $formatter = new MessageFormatter('[{ts}] {method} {uri} HTTP/{version} -> {code} 耗时:{transfer_time}s'); // 替换为你的日志实例(如Monolog\Logger) $yourLogger = new \Monolog\Logger('guzzle_log'); $yourLogger->pushHandler(new \Monolog\Handler\StreamHandler('guzzle.log')); // 创建日志中间件 $loggerMiddleware = Middleware::log($yourLogger, $formatter); $handler = new CurlMultiHandler(); $stack = HandlerStack::create($handler); $stack->push($loggerMiddleware); // 将中间件加入栈 $client = new Client([ 'handler' => $stack, 'headers' => ['Accept-Encoding' => 'gzip, deflate'], 'decode_content' => true ]);
方式二:自定义异步兼容的日志中间件
手动处理Promise的成功/失败状态,确保捕获响应或错误信息:
use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; $loggerMiddleware = function (callable $handler) { return function (RequestInterface $request, array $options) use ($handler) { return $handler($request, $options)->then( // 成功响应时记录日志 function (ResponseInterface $response) use ($request) { $logContent = sprintf( "请求成功:%s %s | 状态码:%d | 响应大小:%d字节", $request->getMethod(), $request->getUri()->__toString(), $response->getStatusCode(), $response->getBody()->getSize() ); // 替换为你的日志写入逻辑 error_log($logContent); return $response; }, // 请求失败时记录错误 function (\Exception $e) use ($request) { $logContent = sprintf( "请求失败:%s %s | 错误信息:%s", $request->getMethod(), $request->getUri()->__toString(), $e->getMessage() ); // 替换为你的日志写入逻辑 error_log($logContent); throw $e; } ); }; }; $handler = new CurlMultiHandler(); $stack = HandlerStack::create($handler); $stack->push($loggerMiddleware); $client = new Client([ 'handler' => $stack, 'headers' => ['Accept-Encoding' => 'gzip, deflate'], 'decode_content' => true ]);
关键说明
先修复cURL编码错误,因为$context['response']无效本质是请求未成功获取到响应,只有请求正常完成后,日志中间件才能捕获到有效的响应数据。
内容的提问来源于stack exchange,提问作者TKoL
相关产品推荐
相关产品推荐

