Guzzlehttp - Wie erhält man den Text einer Antwort von Guzzle 6?

171

Ich versuche, einen Wrapper um eine API zu schreiben, die mein Unternehmen entwickelt. Es ist erholsam und mit Postman kann ich eine Post-Anfrage an einen Endpunkt senden, beispielsweise http://subdomain.dev.myapi.com/api/v1/auth/mit einem Benutzernamen und einem Passwort als POST-Daten, und mir wird ein Token zurückgegeben. Alles funktioniert wie erwartet. Wenn ich jetzt versuche, dasselbe mit PHP zu tun, erhalte ich ein GuzzleHttp\Psr7\ResponseObjekt zurück, kann aber das Token anscheinend nicht darin finden, wie ich es bei der Postman-Anfrage getan habe.

Der relevante Code sieht folgendermaßen aus:

$client = new Client(['base_uri' => 'http://companysub.dev.myapi.com/']);
$response = $client->post('api/v1/auth/', [
    'form_params' => [
        'username' => $user,
        'password' => $password
    ]
]);

var_dump($response); //or $resonse->getBody(), etc...

Die Ausgabe des obigen Codes sieht ungefähr so ​​aus (Warnung, eingehende Textwand):

object(guzzlehttp\psr7\response)#36 (6) {
  ["reasonphrase":"guzzlehttp\psr7\response":private]=>
  string(2) "ok"
  ["statuscode":"guzzlehttp\psr7\response":private]=>
  int(200)
  ["headers":"guzzlehttp\psr7\response":private]=>
  array(9) {
    ["connection"]=>
    array(1) {
      [0]=>
      string(10) "keep-alive"
    }
    ["server"]=>
    array(1) {
      [0]=>
      string(15) "gunicorn/19.3.0"
    }
    ["date"]=>
    array(1) {
      [0]=>
      string(29) "sat, 30 may 2015 17:22:41 gmt"
    }
    ["transfer-encoding"]=>
    array(1) {
      [0]=>
      string(7) "chunked"
    }
    ["content-type"]=>
    array(1) {
      [0]=>
      string(16) "application/json"
    }
    ["allow"]=>
    array(1) {
      [0]=>
      string(13) "post, options"
    }
    ["x-frame-options"]=>
    array(1) {
      [0]=>
      string(10) "sameorigin"
    }
    ["vary"]=>
    array(1) {
      [0]=>
      string(12) "cookie, host"
    }
    ["via"]=>
    array(1) {
      [0]=>
      string(9) "1.1 vegur"
    }
  }
  ["headerlines":"guzzlehttp\psr7\response":private]=>
  array(9) {
    ["connection"]=>
    array(1) {
      [0]=>
      string(10) "keep-alive"
    }
    ["server"]=>
    array(1) {
      [0]=>
      string(15) "gunicorn/19.3.0"
    }
    ["date"]=>
    array(1) {
      [0]=>
      string(29) "sat, 30 may 2015 17:22:41 gmt"
    }
    ["transfer-encoding"]=>
    array(1) {
      [0]=>
      string(7) "chunked"
    }
    ["content-type"]=>
    array(1) {
      [0]=>
      string(16) "application/json"
    }
    ["allow"]=>
    array(1) {
      [0]=>
      string(13) "post, options"
    }
    ["x-frame-options"]=>
    array(1) {
      [0]=>
      string(10) "sameorigin"
    }
    ["vary"]=>
    array(1) {
      [0]=>
      string(12) "cookie, host"
    }
    ["via"]=>
    array(1) {
      [0]=>
      string(9) "1.1 vegur"
    }
  }
  ["protocol":"guzzlehttp\psr7\response":private]=>
  string(3) "1.1"
  ["stream":"guzzlehttp\psr7\response":private]=>
  object(guzzlehttp\psr7\stream)#27 (7) {
    ["stream":"guzzlehttp\psr7\stream":private]=>
    resource(40) of type (stream)
    ["size":"guzzlehttp\psr7\stream":private]=>
    null
    ["seekable":"guzzlehttp\psr7\stream":private]=>
    bool(true)
    ["readable":"guzzlehttp\psr7\stream":private]=>
    bool(true)
    ["writable":"guzzlehttp\psr7\stream":private]=>
    bool(true)
    ["uri":"guzzlehttp\psr7\stream":private]=>
    string(10) "php://temp"
    ["custommetadata":"guzzlehttp\psr7\stream":private]=>
    array(0) {
    }
  }
}

Die Ausgabe von Postman war ungefähr so:

{
    "data" : {
        "token" "fasdfasf-asfasdfasdf-sfasfasf"
    }
}

Offensichtlich fehlt mir etwas an der Arbeit mit den Antwortobjekten in Guzzle. Die Guzzle-Antwort zeigt einen 200-Statuscode in der Anforderung an, sodass ich nicht genau weiß, was ich tun muss, um die zurückgegebenen Daten abzurufen.

Greg
quelle
35
$response->getBody()->getContents()funktioniert nicht?
Federkun

Antworten:

462

Guzzle implementiert PSR-7 . Das bedeutet, dass der Nachrichtentext standardmäßig in einem Stream gespeichert wird, der temporäre PHP-Streams verwendet. Um alle Daten abzurufen, können Sie den Casting-Operator verwenden:

$contents = (string) $response->getBody();

Sie können es auch mit tun

$contents = $response->getBody()->getContents();

Der Unterschied zwischen den beiden Ansätzen besteht darin, dass getContentsder verbleibende Inhalt zurückgegeben wird, sodass ein zweiter Aufruf nichts zurückgibt, es sei denn, Sie suchen die Position des Streams mit rewindoder seek.

$stream = $response->getBody();
$contents = $stream->getContents(); // returns all the contents
$contents = $stream->getContents(); // empty string
$stream->rewind(); // Seek to the beginning
$contents = $stream->getContents(); // returns all the contents

Stattdessen werden unter Verwendung der String-Casting-Operationen von PHP alle Daten vom Anfang bis zum Ende aus dem Stream gelesen.

$contents = (string) $response->getBody(); // returns all the contents
$contents = (string) $response->getBody(); // returns all the contents

Dokumentation: http://docs.guzzlephp.org/en/latest/psr7.html#responses

Federkun
quelle
5
Die Funktion getContents befindet sich nur in einem kleinen Teil der Guzzle 6-Dokumentation (im Abschnitt "Streams"), und ich habe sie verpasst. Du hast mich vor vielen Suchen bewahrt.
Maximus
58
VIELEN DANK. Es ist unglaublich, dass dies in der Dokumentation nicht klarer ist. Selbst die offizielle Dokumentation ( docs.guzzlephp.org/en/latest ) lässt den Eindruck entstehen, dass der Aufruf von $ res-> getBody () das zurückgibt, was Sie normalerweise erwarten würden.
John
24
Sie sollten wirklich so etwas wie eine Notiz oder einen Hinweis in die offiziellen Dokumente einfügen. Ich habe zwei Tage mit diesem Thema verschwendet.
cwhsu
+1 In der Guzzle-Dokumentation wird dies fälschlicherweise angegeben "you can pass true to this method [getBody()] to retrieve the body as a string.". Das scheint für mich mit Guzzle 6 nicht zu funktionieren, aber das Casting in einen String oder mit getContents () funktioniert.
Magnus W
8
Sie können auch json_decode verwenden. Wenn Sie beispielsweise Ihre Antwort in json_decode($response, true);diese Zeile einschließen, wird ein Array zurückgegeben.
Sygon
17

Wenn Sie JSON wieder erwarten, ist dies der einfachste Weg:

$data = json_decode($response->getBody()); // returns an object

// OR

$data = json_decode($response->getBody(), true); // returns an array

json_decode()Wirft den Körper automatisch auf string, sodass kein Anruf erforderlich ist getContents().

Maksim Ivanov
quelle
1
Warum bekommt diese Antwort nicht mehr Aufmerksamkeit ??? Genau das brauchte ich. Danke @MaskimIvanov
Eric McWinNEr
Das war auch für mich das Einfachste und Leichteste. Danke
Alator
Diese einfache Antwort "löst" das unmittelbare Problem, verfehlt jedoch die Nuance der von @Federkun akzeptierten Antwort. Der Grund, warum dies die meiste Zeit "nur funktioniert", ist, dass der Aufruf zum json_decode impliziten Umwandeln des Antwortkörpers als Zeichenfolge. Trotzdem lohnt es sich, die akzeptierte Antwort zu verstehen, da es Probleme mit dem String Casting-Ansatz geben kann, bei dem nicht immer alle Daten abgerufen werden, wie im Kommentar von @Shardj hervorgehoben.
13.
Diese Methode funktioniert, verursacht jedoch Fehler während der statischen Analyse
7.
0

So erhalten Sie eine Antwort im JSON-Format:

  1.$response = (string) $res->getBody();
      $response =json_decode($response); // Using this you can access any key like below
     
     $key_value = $response->key_name; //access key  

  2. $response = json_decode($res->getBody(),true);
     
     $key_value =   $response['key_name'];//access key
Bhargav Variya
quelle