Guzzle 6: Keine json () -Methode mehr für Antworten

172

Zuvor in Guzzle 5.3:

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

Ich könnte leicht ein PHP-Array von einer JSON-Antwort erhalten. In Guzzle 6 weiß ich nicht, wie ich es machen soll. Es scheint keine json()Methode mehr zu geben. Ich habe (schnell) das Dokument aus der neuesten Version gelesen und nichts über JSON-Antworten gefunden. Ich glaube, ich habe etwas verpasst, vielleicht gibt es ein neues Konzept, das ich nicht verstehe (oder vielleicht habe ich nicht richtig gelesen).

Ist dieser (unten) neue Weg der einzige Weg?

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

Oder gibt es einen Helfer oder so etwas?

Rap-2-h
quelle

Antworten:

292

Ich benutze json_decode($response->getBody())jetzt statt $response->json().

Ich vermute, dass dies ein Opfer der PSR-7-Konformität sein könnte.

meriial
quelle
4
Nichts in der Dokumentation, das dies explizit macht, aber es scheint, dass sie den $response->json()Helfer auslaufen lassen .
Büroklammer
60
Wenn Sie eine Array-Antwort erwarten, wie das Original ->json()funktioniert, verwenden Sie json_decode($response->getBody(), true)stattdessen, um ein Array anstelle eines stdObject zu erhalten
Jay El-Kaake
14
Mit strict_typesmusste ich den Guzzle-Antwortkörper in einen String umwandeln, bevor ich ihn dekodierte:json_decode((string) $response->getBody(), true)
Yoan Tournade
112

Sie wechseln zu:

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

Anstelle des anderen Kommentars, wenn Sie möchten, dass es genau wie zuvor funktioniert, um Arrays anstelle von Objekten zu erhalten.

dmyers
quelle
29

Ich verwende $response->getBody()->getContents(), um JSON von der Antwort zu erhalten. Guzzle Version 6.3.0.

jusep
quelle
6
Wenn Sie getContents()den Antworttext aufrufen, getContents()wird der Stream geleert, und der nächste Aufruf von wird leer zurückgegeben. Wenn Sie den Körper als Zeichenfolge erhalten möchten, verwenden Sie:strval($response->getBody())
JVitela
1
Ich wünschte, dieser Kommentar wäre höher. Ich habe meine Antwort mit getContent protokolliert und als ich später eine Zeile analysierte, war mein Array leer. Hat mich Stunden gekostet. Vielen Dank!
Colin
14

Wenn ihr noch interessiert seid, ist hier meine Problemumgehung basierend auf der Guzzle Middleware- Funktion:

  1. Erstellen Sie JsonAwaraResponsediese Content-TypeOption , um die JSON-Antwort per HTTP-Header zu dekodieren. Andernfalls wird sie als Standard-Guzzle-Antwort verwendet:

    <?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. Erstellen Sie eine Middleware, die die Guzzle PSR-7-Antworten durch die oben genannte Antwortimplementierung ersetzt:

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

Verwenden Sie danach Guzzle wie immer, um JSON als natives PHP-Array abzurufen:

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

Getestet mit guzzlehttp / guzzle 6.3.3

Andrew
quelle
Das sind einige gute Sachen. Verwendung in einer Rest API Client-Aufgabe, die ich gerade bei der Arbeit aufgenommen habe. Ich habe jedoch eine Frage zu Ihrer Antwort. War Ihre JsonAwareResponse-Klasse für den GuzzleHttp-Namespace vorgesehen? Am Ende habe ich diese Klasse nur unter meinem eigenen Namespace erstellt, aber für eine Sekunde habe ich in der Codebasis von GuzzleHttp nach dieser Klasse gesucht. :) Danke noch einmal!
Floorz
Verwenden Sie diese Lösung nicht, da sie die PSR-7-Schnittstelle beschädigt MessageInterface. Mit PSR-7 gibt es keine legale Lösung, um diese Schnittstelle zu patchen und dekodierten JSON von der getBody()Methode zurückzugeben.
Sergey Nevmerzhitsky
3

$responseist eine Instanz von PSR-7 ResponseInterface. Weitere Informationen finden Sie unter https://www.php-fig.org/psr/psr-7/#3-interfaces

getBody()Rückgabe StreamInterface:

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

StreamInterfaceimplementiert __toString()was tut

Liest alle Daten aus dem Stream von Anfang bis Ende in eine Zeichenfolge.

Um den Körper als Zeichenfolge zu lesen, müssen Sie ihn daher in eine Zeichenfolge umwandeln:

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


Fallstricke

  1. json_decode($response->getBody()ist nicht die beste Lösung, da es den Stream auf magische Weise für Sie in einen String verwandelt. json_decode()erfordert Zeichenfolge als 1. Argument.
  2. Verwenden $response->getBody()->getContents()Sie es nur, wenn Sie wissen, was Sie tun. Wenn Sie die Dokumentation für lesen getContents(), heißt es : Returns the remaining contents in a string. Daher getContents()liest der Aufruf den Rest des Streams und der erneute Aufruf gibt nichts zurück, da der Stream bereits am Ende ist. Sie müssten den Stream zwischen diesen Anrufen zurückspulen.
simPod
quelle
1

Beim Hinzufügen ->getContents()wird keine jSON-Antwort zurückgegeben, sondern als Text.

Sie können einfach verwenden json_decode

Moh
quelle
Es gibt JSON als Text zurück, nicht als HTML.
František Maša