Guzzle 6:响应不再使用json()方法


Guzzle 6: no more json() method for responses

《Guzzle 5.3》前情提要:

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

我可以很容易地从JSON响应中获得PHP数组。现在在《狂饮6》中,我不知道该怎么做。似乎再也没有json()方法了。我(快速)阅读了最新版本的文档,没有发现任何关于JSON响应的内容。我想我错过了一些东西,也许有一个新概念我不理解(或者我没有读对)。

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

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

或者有一个助手之类的东西?

我现在用json_decode($response->getBody())代替$response->json()

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

切换到:

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

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

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

如果你们仍然感兴趣,这里是我基于Guzzle中间件特性的解决方案:

  1. 创建JsonAwaraResponse,将解码JSON响应Content-Type HTTP头,如果没有-它将作为标准的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;
        }
    }
    
  2. 创建中间件,用上述响应实现取代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

$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()

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

因此,要将body读取为string,必须将其强制转换为string:

$stringBody = $response->getBody()->__toString()


陷阱

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

添加->getContents()不返回jSON响应,而是作为文本返回。

可以直接使用json_decode