Guzzlehttp - Come si ottiene il corpo di una risposta da Guzzle 6?


163

Sto cercando di scrivere un wrapper attorno a un API che la mia azienda sta sviluppando. È riposante e usando Postman posso inviare una richiesta di post a un endpoint come http://subdomain.dev.myapi.com/api/v1/auth/con un nome utente e una password come dati POST e mi viene restituito un token. Tutto funziona come previsto. Ora, quando provo a fare lo stesso con PHP, torno indietro un GuzzleHttp\Psr7\Responseoggetto, ma non riesco a trovare il token da nessuna parte al suo interno come ho fatto con la richiesta Postman.

Il codice rilevante è simile a:

$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...

L'output del codice sopra sembra qualcosa di simile (avviso, muro di testo in arrivo):

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) {
    }
  }
}

L'output di Postman è stato qualcosa del tipo:

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

Chiaramente mi manca qualcosa nel lavorare con gli oggetti response in Guzzle. La risposta di Guzzle indica un codice di stato 200 sulla richiesta, quindi non sono sicuro di cosa esattamente devo fare per recuperare i dati restituiti.


33
$response->getBody()->getContents()non funziona?
Federkun,

Risposte:


437

Guzzle implementa PSR-7 . Ciò significa che per impostazione predefinita memorizzerà il corpo di un messaggio in uno Stream che utilizza flussi temporali PHP. Per recuperare tutti i dati, è possibile utilizzare l'operatore di casting:

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

Puoi anche farlo con

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

La differenza tra i due approcci è che getContentsrestituisce i contenuti rimanenti, in modo che una seconda chiamata non restituisca nulla a meno che non si cerchi la posizione dello stream con rewindo 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

Invece, utilizzando le operazioni di casting delle stringhe di PHP, leggerà tutti i dati dallo stream dall'inizio fino alla fine.

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

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


5
La funzione getContents è solo in una piccola parte della documentazione di Guzzle 6 (nella sezione stream), e l'ho persa. Mi hai salvato da molte ricerche.
Massimo

58
GRAZIE. È incredibile che ciò non sia più chiaro nella documentazione. Anche la loro documentazione ufficiale ( docs.guzzlephp.org/en/latest ) fa sembrare che chiamare $ res-> getBody () restituisca ciò che normalmente ti aspetteresti.
John,

24
Dovrebbero davvero inserire qualcosa come una nota o un avviso nei documenti ufficiali. Ho perso due giorni su questo problema.
cwhsu,

+1 La documentazione di Guzzle afferma erroneamente che "you can pass true to this method [getBody()] to retrieve the body as a string.". Questo non sembra funzionare per me usando Guzzle 6, ma il casting su stringa o usando getContents () funziona.
Magnus W,

8
Puoi anche usare json_decode. Ad esempio, avvolgere la risposta in json_decode($response, true);questo restituirà un array.
Sygon,

13

Se ti aspetti JSON indietro, il modo più semplice per ottenerlo:

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

// OR

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

json_decode()lancerà automaticamente il corpo su string, quindi non è necessario chiamare getContents().


1
Perché questa risposta non sta attirando più attenzione ??? Questo è esattamente ciò di cui avevo bisogno. Grazie @MaskimIvanov
Eric McWinNEr il

Questa è stata la cosa più semplice e facile anche per me. Grazie
Alator il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.