You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 08:10:26