狂饮6:没有更多的json()方法来响应


172

以前在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']);

还是有帮手或类似的东西?

Answers:


292

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

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


4
文档中没有任何东西可以使这一点变得明确,但是看起来他们已经逐步淘汰了该$response->json()助手。
回形针

60
如果您期望像原始数组那样的数组响应->json(),请改用json_decode($response->getBody(), true)获取数组而不是stdObject
Jay El-Kaake 2015年

14
使用strict_types,我需要先将Guzzle响应主体转换为字符串,然后再对其进行解码:json_decode((string) $response->getBody(), true)
Yoan Tournade

我一直喜欢使用\GuzzleHttp\json_decode(或\GuzzleHttp\Utils::jsonDecode取决于您使用的Guzzle版本)对兼容的签名\json_decode,但是如果出现错误,则会利用适当的err处理抛出异常。
AdrianFöder9

112

您切换到:

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

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


29

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


6
调用getContents()响应主体将清空流,而对的下一个调用getContents()将返回空。如果要以字符串形式获取主体,请使用:strval($response->getBody())
JVitela '18

1
我希望这个评论更高。我正在使用getContent记录响应,当我稍后解析一行时,我的数组为空。花了我几个小时。谢谢!
科林

14

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

  1. 创建JsonAwaraResponse将通过Content-TypeHTTP标头解码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;
        }
    }
  2. 创建中间件,该中间件将用上面的Response实现替换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 Client任务中使用。我确实有一个关于您答案的问题。您的JsonAwareResponse类是否打算位于GuzzleHttp命名空间下?我最终只是在自己的名称空间下创建了该类,但是有一秒钟我正在GuzzleHttp的代码库中搜索以寻找该类。:) 再次感谢!
floorz

不要使用此解决方案,因为它会破坏PSR-7接口MessageInterface。对于PSR-7,没有合法的解决方案来修补此接口以从getBody()方法返回解码的JSON 。
Sergey Nevmerzhitsky

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:

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


陷阱

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

1

添加->getContents()不会返回jSON响应,而是以文本形式返回。

您可以简单地使用 json_decode


它以文本而不是HTML的形式返回JSON。
弗朗MASA
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.