Guzzle 6: não há mais método json () para respostas


172

Anteriormente no Guzzle 5.3:

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

Eu poderia facilmente obter uma matriz PHP a partir de uma resposta JSON. Agora, no Guzzle 6, não sei como fazer. Parece não haver json()mais método. Li (rapidamente) o documento da versão mais recente e não encontrei nada sobre as respostas JSON. Acho que perdi alguma coisa, talvez haja um novo conceito que não entendo (ou talvez não tenha lido corretamente).

Esta (abaixo) nova maneira é a única maneira?

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

Ou existe um ajudante ou algo assim?

Respostas:


292

Eu uso json_decode($response->getBody())agora em vez de $response->json().

Eu suspeito que isso possa ser uma vítima da conformidade com o PSR-7.


4
Nada na documentação que torna isso explícito, mas parece que eles eliminaram o $response->json()auxiliar.
paperclip

60
Se você está esperando uma resposta matriz como forma como o original ->json()funcionou, uso json_decode($response->getBody(), true), em vez de obter uma matriz em vez de um stdObject
Jay El-Kaake

14
Usando strict_types, eu precisava moldar o corpo da resposta Guzzle antes de decodificá-lo:json_decode((string) $response->getBody(), true)
Yoan Tournade 23/03

Eu sempre gostei de usar \GuzzleHttp\json_decode(ou \GuzzleHttp\Utils::jsonDecodedependendo da versão do Guzzle que você está) que tem uma assinatura compatível \json_decode, mas gera uma exceção se houver um erro, alavancando o tratamento adequado dos erros.
Adrian Föder

112

Você muda para:

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

Em vez do outro comentário, se você deseja que ele funcione exatamente como antes, para obter matrizes em vez de objetos.


29

Eu uso $response->getBody()->getContents()para obter JSON de resposta. Guzzle versão 6.3.0.


6
A chamada getContents()no corpo da resposta esvaziará o fluxo e a próxima chamada para getContents()retornará vazia. Se você quiser obter o corpo como o uso string:strval($response->getBody())
JVitela

1
Eu gostaria que este comentário fosse mais alto. Eu estava registrando minha resposta usando getContent e quando fui analisar uma linha mais tarde, minha matriz estava vazia. Me custou horas. Obrigado!
Colin

14

Se vocês ainda estão interessados, aqui está minha solução alternativa, com o recurso de middleware Guzzle :

  1. Crie JsonAwaraResponseque decodifique a resposta JSON pelo Content-Typecabeçalho HTTP, se não - ele atuará como resposta padrão do 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. Crie o Middleware que substituirá as respostas do Guzzle PSR-7 pela implementação de resposta acima:

    <?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');

Depois disso, para recuperar o JSON como matriz nativa do PHP, use o Guzzle como sempre:

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

Testado com guzzlehttp / guzzle 6.3.3


Isso é uma coisa boa. Usando em uma tarefa do Rest API Client que acabei de pegar no trabalho. Mas eu tenho uma pergunta sobre sua resposta. Sua classe JsonAwareResponse estava destinada ao espaço de nomes GuzzleHttp? Acabei criando essa classe com meu próprio espaço para nome, mas por um segundo eu estava pesquisando na base de código do GuzzleHttp procurando por essa classe. :) Obrigado novamente!
floorz

Não use esta solução porque ela quebra a interface PSR-7 MessageInterface. Com o PSR-7, não há solução legal para corrigir esta interface para retornar o JSON decodificado do getBody()método.
Sergey Nevmerzhitsky

3

$responseé uma instância do PSR-7 ResponseInterface. Para mais detalhes, consulte https://www.php-fig.org/psr/psr-7/#3-interfaces

getBody()retorna StreamInterface:

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

StreamInterfaceimplementa o __toString()que faz

Lê todos os dados do fluxo em uma sequência, do começo ao fim.

Portanto, para ler o corpo como string, você deve convertê-lo em string:

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


Pegadinhas

  1. json_decode($response->getBody()não é a melhor solução, pois lança magicamente o fluxo em seqüência para você. json_decode()requer string como 1º argumento.
  2. Não use a $response->getBody()->getContents()menos que saiba o que está fazendo. Se você ler a documentação para getContents(), ele diz: Returns the remaining contents in a string. Portanto, a chamada getContents()lê o restante do fluxo e a chamada novamente não retorna nada porque o fluxo já está no final. Você teria que rebobinar o fluxo entre essas chamadas.

1

A adição ->getContents()não retorna a resposta jSON, mas retorna como texto.

Você pode simplesmente usar json_decode


Retorna JSON como texto, não HTML.
František Maša
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.