Guzzle 6: brak metody json () dla odpowiedzi


172

Wcześniej w Guzzle 5.3:

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

Mogłem łatwo uzyskać tablicę PHP z odpowiedzi JSON. Teraz w Guzzle 6 nie wiem, jak to zrobić. Wydaje się, że nie ma json()już metody. Przeczytałem (szybko) dokument z najnowszej wersji i nie znalazłem nic o odpowiedziach JSON. Myślę, że coś przeoczyłem, może jest nowa koncepcja, której nie rozumiem (a może nie przeczytałem poprawnie).

Czy to (poniżej) nowy sposób jest jedynym sposobem?

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

A może jest pomocnik lub coś takiego?

Odpowiedzi:


292

Używam json_decode($response->getBody())teraz zamiast $response->json().

Podejrzewam, że może to być ofiara przestrzegania PSR-7.


4
W dokumentacji nie ma nic, co by to jednoznacznie wskazywało, ale wygląda na to, że wycofali $response->json()pomocnika.
spinacz

60
Jeśli spodziewasz się odpowiedzi tablicowej, takiej jak ->json()działała oryginał , użyj json_decode($response->getBody(), true)zamiast tego, aby uzyskać tablicę zamiast stdObject
Jay El-Kaake,

14
Używając strict_types, musiałem rzucić treść odpowiedzi Guzzle na łańcuch przed jej odkodowaniem:json_decode((string) $response->getBody(), true)
Yoan Tournade

Zawsze lubiłem używać \GuzzleHttp\json_decode(lub w \GuzzleHttp\Utils::jsonDecodezależności od wersji Guzzle), który ma zgodny podpis \json_decode, ale zgłasza wyjątek, jeśli wystąpi błąd, wykorzystując odpowiednią obsługę błędów.
Adrian Föder

112

Przełączasz się na:

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

Zamiast drugiego komentarza, jeśli chcesz, aby działał dokładnie tak, jak poprzednio, aby uzyskać tablice zamiast obiektów.


29

Używam, $response->getBody()->getContents()aby uzyskać JSON z odpowiedzi. Guzzle w wersji 6.3.0.


6
Wywołanie getContents()w treści odpowiedzi spowoduje opróżnienie strumienia, a następne wywołanie getContents()zwróci puste. Jeśli chcesz uzyskać ciało jako ciąg, użyj:strval($response->getBody())
JVitela

1
Chciałbym, żeby ten komentarz był wyższy. Rejestrowałem swoją odpowiedź za pomocą getContent, a kiedy poszedłem później przeanalizować wiersz, moja tablica była pusta. Kosztują mnie godziny. Dzięki!
Colin

14

Jeśli nadal jesteś zainteresowany, oto moje obejście oparte na funkcji oprogramowania pośredniego Guzzle :

  1. Utwórz JsonAwaraResponse, który zdekoduje odpowiedź JSON przez Content-Typenagłówek HTTP, jeśli nie - będzie działać jako standardowa odpowiedź 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. Utwórz oprogramowanie pośredniczące, które zastąpi odpowiedzi Guzzle PSR-7 powyższą implementacją odpowiedzi:

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

Następnie, aby pobrać JSON jako natywną tablicę PHP, użyj Guzzle jak zawsze:

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

Przetestowano za pomocą guzzlehttp / guzzle 6.3.3


To jest niezła rzecz. Korzystanie z zadania klienta Rest API, które właśnie wykonałem w pracy. Mam jednak jedno pytanie dotyczące Twojej odpowiedzi. Czy Twoja klasa JsonAwareResponse miała znajdować się w przestrzeni nazw GuzzleHttp? Skończyło się na utworzeniu tej klasy w mojej własnej przestrzeni nazw, ale przez sekundę przeszukiwałem bazę kodu GuzzleHttp w poszukiwaniu tej klasy. :) Dzięki jeszcze raz!
floorz

Nie używaj tego rozwiązania, ponieważ psuje interfejs PSR-7 MessageInterface. W PSR-7 nie ma legalnego rozwiązania, aby załatać ten interfejs w celu zwrócenia zdekodowanego JSON z getBody()metody.
Sergey Nevmerzhitsky

3

$responsejest instancją PSR-7 ResponseInterface. Aby uzyskać więcej informacji, zobacz https://www.php-fig.org/psr/psr-7/#3-interfaces

getBody()zwraca StreamInterface:

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

StreamInterfacenarzędzia, __toString()które to robią

Odczytuje wszystkie dane ze strumienia do ciągu, od początku do końca.

Dlatego, aby odczytać ciało jako ciąg, musisz rzucić je na łańcuch:

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


Gotchas

  1. json_decode($response->getBody()nie jest najlepszym rozwiązaniem, ponieważ w magiczny sposób rzuca strumień na sznurek. json_decode()wymaga łańcucha jako pierwszego argumentu.
  2. Nie używaj, $response->getBody()->getContents()chyba że wiesz, co robisz. Jeśli czytać dokumentację getContents(), to mówi: Returns the remaining contents in a string. Dlatego wywołanie getContents()odczytuje resztę strumienia, a wywołanie go ponownie nie zwraca niczego, ponieważ strumień jest już na końcu. Musiałbyś przewijać strumień między tymi połączeniami.

1

Dodanie ->getContents()nie zwraca odpowiedzi jSON, zamiast tego zwraca jako tekst.

Możesz po prostu użyć json_decode


Zwraca JSON jako tekst, a nie HTML.
František Maša
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.