Guzzle 6:不再有响应的 json() 方法

Posted

技术标签:

【中文标题】Guzzle 6:不再有响应的 json() 方法【英文标题】:Guzzle 6: no more json() method for responses 【发布时间】:2015-08-12 08:31:25 【问题描述】:

Guzzle 5.3 之前的版本:

$response = $client->get('http://httpbin.org/get');
$array = $response->json(); // Yoohoo
var_dump($array[0]['origin']);

我可以轻松地从 JSON 响应中获取 php 数组。现在在 Guzzle 6 中,我不知道该怎么做。似乎没有 json() 方法了。我(很快)阅读了最新版本的文档,没有发现任何关于 JSON 响应的信息。我想我错过了一些东西,也许有一个我不理解的新概念(或者我没有正确阅读)。

这是(下面的)新方法唯一的方法吗?

$response = $client->get('http://httpbin.org/get');
$array = json_decode($response->getBody()->getContents(), true); // :'(
var_dump($array[0]['origin']);

或者有没有帮手之类的?

【问题讨论】:

【参考方案1】:

我现在使用json_decode($response->getBody()) 而不是$response->json()

我怀疑这可能是 PSR-7 合规性的牺牲品。

【讨论】:

文档中没有明确说明这一点,但似乎他们已经逐步淘汰了 $response->json() 助手。 如果您期望数组响应类似于原始 ->json() 的工作方式,请使用 json_decode($response->getBody(), true) 来获取数组而不是 stdObject 使用strict_types,我需要在解码之前将 Guzzle 响应正文转换为字符串:json_decode((string) $response->getBody(), true) 我一直喜欢使用\GuzzleHttp\json_decode(或\GuzzleHttp\Utils::jsonDecode,具体取决于您使用的 Guzzle 版本),它与\json_decode 具有兼容的签名,但如果出现错误则会引发异常,利用适当的错误处理。 strict_types 下,您可以按照@YoanTournade 的建议强制转换为string,或者使用返回字符串的$response->getBody()->getContents()【参考方案2】:

你切换到:

json_decode($response->getBody(), true)

如果您希望它完全像以前一样工作以获取数组而不是对象,而不是其他注释。

【讨论】:

【参考方案3】:

我使用$response->getBody()->getContents() 从响应中获取 JSON。 Guzzle 版本 6.3.0。

【讨论】:

在响应正文中调用getContents() 将清空流,而对getContents() 的下一次调用将返回空。如果您想将正文作为字符串使用:strval($response->getBody()) 我希望这个评论更高。我正在使用 getContent 记录我的响应,当我稍后去解析一行时,我的数组是空的。花了我几个小时。谢谢!【参考方案4】:

如果你们仍然感兴趣,这是我基于 Guzzle middleware 功能的解决方法:

    创建JsonAwaraResponse,它将通过Content-Type HTTP 标头解码 JSON 响应,如果不是 - 它将充当标准 Guzzle 响应:

    <?php
    
    namespace GuzzleHttp\Psr7;
    
    
    class JsonAwareResponse extends Response
    
        /**
         * Cache for performance
         * @var array
         */
        private $json;
    
        public function getBody()
        
            if ($this->json) 
                return $this->json;
            
            // get parent Body stream
            $body = parent::getBody();
    
            // if JSON HTTP header detected - then decode
            if (false !== strpos($this->getHeaderLine('Content-Type'), 'application/json')) 
                return $this->json = \json_decode($body, true);
            
            return $body;
        
    
    

    创建Middleware,它将用上述响应实现替换 Guzzle PSR-7 响应:

    <?php
    
    $client = new \GuzzleHttp\Client();
    
    /** @var HandlerStack $handler */
    $handler = $client->getConfig('handler');
    $handler->push(\GuzzleHttp\Middleware::mapResponse(function (\Psr\Http\Message\ResponseInterface $response) 
        return new \GuzzleHttp\Psr7\JsonAwareResponse(
            $response->getStatusCode(),
            $response->getHeaders(),
            $response->getBody(),
            $response->getProtocolVersion(),
            $response->getReasonPhrase()
        );
    ), 'json_decode_middleware');
    

在此之后将 JSON 作为 PHP 原生数组检索,一如既往地使用 Guzzle:

$jsonArray = $client->get('http://httpbin.org/headers')->getBody();

用 guzzlehttp/guzzle 6.3.3 测试

【讨论】:

这是一些好东西。在我刚刚在工作中获得的 Rest API 客户端任务中使用。不过,我确实对您的回答有一个问题。您的 JsonAwareResponse 类是否打算位于 GuzzleHttp 命名空间下?我最终只是在我自己的命名空间下创建了那个类,但是我在 GuzzleHttp 的代码库中搜索了一秒钟来寻找那个类。 :) 再次感谢! 不要使用这个解决方案,因为它破坏了 PSR-7 接口MessageInterface。对于 PSR-7,没有合法的解决方案可以修补此接口以从 getBody() 方法返回解码的 JSON。 @SergeyNevmerzhitsky 提到的问题的潜在解决方案可能是将 JsonAwareResponse 转换为装饰器,然后实现 __call() 将调用转发到实际响应。然后你可以添加getJson() 或任何你想要的。【参考方案5】:

$response 是 PSR-7 ResponseInterface 的实例。更多详情见https://www.php-fig.org/psr/psr-7/#3-interfaces

getBody() 返回StreamInterface

/**
 * Gets the body of the message.
 *
 * @return StreamInterface Returns the body as a stream.
 */
public function getBody();

StreamInterface 实现了__toString()

将流中的所有数据从头到尾读入一个字符串。

因此,要将正文读取为字符串,您必须将其转换为字符串:

$stringBody = (string) $response-&gt;getBody()


陷阱

    json_decode($response-&gt;getBody() 不是最好的解决方案,因为它神奇地将流转换为字符串。 json_decode() 需要字符串作为第一个参数。 除非您知道自己在做什么,否则不要使用$response-&gt;getBody()-&gt;getContents()。如果您阅读getContents() 的文档,它会说:Returns the remaining contents in a string。因此,调用getContents() 会读取流的其余部分并再次调用它不会返回任何内容,因为流已经在末尾。您必须在这些呼叫之间倒带。

【讨论】:

【参考方案6】:

添加 -&gt;getContents() 不会返回 JSON 响应,而是以文本形式返回。

您可以简单地使用json_decode

【讨论】:

它将 JSON 作为文本返回,而不是 html

以上是关于Guzzle 6:不再有响应的 json() 方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Guzzle ~6.0 中读取响应有效 URL

如何使用 Guzzle 和 Laravel 从 JSON 响应中提取单个数组值

Guzzlehttp - 如何从 Guzzle 6 获取响应的正文?

你可以在 Guzzle POST Body 中包含原始 JSON 吗?

PHP 使用 Guzzle 执行 HTTP 请求

PHP 使用 Guzzle 执行 HTTP 请求