Guzzlehttp - ¿Cómo obtener el cuerpo de una respuesta de Guzzle 6?

163

Estoy tratando de escribir un contenedor alrededor de una API que mi empresa está desarrollando. Es tranquilo, y con Postman puedo enviar una solicitud de publicación a un punto final como http://subdomain.dev.myapi.com/api/v1/auth/con un nombre de usuario y contraseña como datos POST y me devuelven un token. Todo funciona como se esperaba. Ahora, cuando intento hacer lo mismo desde PHP, recupero un GuzzleHttp\Psr7\Responseobjeto, pero parece que no puedo encontrar el token en ningún lugar como lo hice con la solicitud de Postman.

El código relevante se ve así:

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

El resultado del código anterior se parece a (advertencia, muro de texto entrante):

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

El resultado de Postman fue algo así como:

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

Claramente me falta algo sobre trabajar con los objetos de respuesta en Guzzle. La respuesta de Guzzle indica un código de estado 200 en la solicitud, por lo que no estoy seguro de qué debo hacer exactamente para recuperar los datos devueltos.

Greg
fuente
33
$response->getBody()->getContents()no funciona
Federkun

Respuestas:

436

Guzzle implementa PSR-7 . Eso significa que, de forma predeterminada, almacenará el cuerpo de un mensaje en una secuencia que utiliza secuencias temporales de PHP. Para recuperar todos los datos, puede usar el operador de conversión:

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

También puedes hacerlo con

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

La diferencia entre los dos enfoques es que getContentsdevuelve el contenido restante, de modo que una segunda llamada no devuelve nada a menos que busque la posición de la secuencia 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

En cambio, utilizando las operaciones de conversión de cadenas de PHP, leerá todos los datos de la secuencia desde el principio hasta el final.

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

Documentación: http://docs.guzzlephp.org/en/latest/psr7.html#responses

Federkun
fuente
55
La función getContents solo se encuentra en una pequeña parte de la documentación de Guzzle 6 (en la sección de secuencias), y me la perdí. Me salvaste de muchas búsquedas.
Maximus
58
GRACIAS. Es increíble que esto no esté más claro en la documentación. Incluso su documentación oficial ( docs.guzzlephp.org/en/latest ) hace que parezca que llamar a $ res-> getBody () devuelve lo que normalmente esperaría.
John
24
Realmente deberían poner algo como una nota o aviso en los documentos oficiales. Perdí dos días en este tema.
cwhsu
+1 La documentación de Guzzle lo afirma falsamente "you can pass true to this method [getBody()] to retrieve the body as a string.". Eso no parece funcionar para mí usando Guzzle 6, pero convertir en cadena o usar getContents () sí funciona.
Magnus W
8
También puedes usar json_decode. Por ejemplo, envuelva su respuesta en json_decode($response, true);esto devolverá una matriz.
Sygon
13

Si espera volver a JSON, la forma más sencilla de obtenerlo:

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

// OR

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

json_decode()lanzará automáticamente el cuerpo string, por lo que no hay necesidad de llamar getContents().

Maksim Ivanov
fuente
1
¿Por qué esta respuesta no recibe más atención? Esto es precisamente lo que necesitaba. Gracias @MaskimIvanov
Eric McWinNEr
Eso fue lo más simple y fácil para mí también. Gracias
Alator