#php #laravel #guzzle
#php #ответ #guzzle #guzzle6
Вопрос:
Я пытаюсь написать оболочку вокруг API, который разрабатывает моя компания. Это restful, и с помощью Postman я могу отправить post-запрос на конечную точку, например http://subdomain.dev.myapi.com/api/v1/auth/
, с именем пользователя и паролем в качестве POST-данных, и мне возвращается токен. Все работает, как ожидалось. Теперь, когда я пытаюсь сделать то же самое с PHP, я получаю обратно GuzzleHttpPsr7Response
объект, но, похоже, нигде не могу найти токен внутри него, как я сделал с запросом Postman.
Соответствующий код выглядит следующим образом:
$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...
Вывод приведенного выше кода выглядит примерно так (предупреждение, входящая стена текста):
object(guzzlehttppsr7response)#36 (6) {
["reasonphrase":"guzzlehttppsr7response":private]=>
string(2) "ok"
["statuscode":"guzzlehttppsr7response":private]=>
int(200)
["headers":"guzzlehttppsr7response":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":"guzzlehttppsr7response":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":"guzzlehttppsr7response":private]=>
string(3) "1.1"
["stream":"guzzlehttppsr7response":private]=>
object(guzzlehttppsr7stream)#27 (7) {
["stream":"guzzlehttppsr7stream":private]=>
resource(40) of type (stream)
["size":"guzzlehttppsr7stream":private]=>
null
["seekable":"guzzlehttppsr7stream":private]=>
bool(true)
["readable":"guzzlehttppsr7stream":private]=>
bool(true)
["writable":"guzzlehttppsr7stream":private]=>
bool(true)
["uri":"guzzlehttppsr7stream":private]=>
string(10) "php://temp"
["custommetadata":"guzzlehttppsr7stream":private]=>
array(0) {
}
}
}
Вывод Postman был примерно таким:
{
"data" : {
"token" "fasdfasf-asfasdfasdf-sfasfasf"
}
}
Очевидно, я что-то упускаю из виду в работе с объектами ответа в Guzzle. Ответ Guzzle указывает код состояния 200 в запросе, поэтому я не совсем уверен, что мне нужно сделать, чтобы получить возвращенные данные.
Комментарии:
1.
$response->getBody()->getContents()
не работает?
Ответ №1:
Guzzle реализует PSR-7. Это означает, что по умолчанию он будет сохранять тело сообщения в потоке, который использует временные потоки PHP. Чтобы получить все данные, вы можете использовать оператор приведения:
$contents = (string) $response->getBody();
Вы также можете сделать это с помощью
$contents = $response->getBody()->getContents();
Разница между двумя подходами заключается в том, что getContents
возвращает оставшееся содержимое, так что второй вызов ничего не возвращает, если вы не ищете позицию потока с rewind
помощью или 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
Вместо этого, используя операции приведения строк PHP, он будет считывать все данные из потока с начала до достижения конца.
$contents = (string) $response->getBody(); // returns all the contents
$contents = (string) $response->getBody(); // returns all the contents
Документация: http://docs.guzzlephp.org/en/latest/psr7.html#responses
Комментарии:
1. Функция getContents есть только в одной небольшой части документации Guzzle 6 (в разделе streams), и я ее пропустил. Вы избавили меня от множества поисков.
2. Спасибо. Невероятно, что это не более понятно в документации. Даже их официальная документация ( docs.guzzlephp.org/en/latest ) создает впечатление, что вызов $res->getBody() возвращает то, что вы обычно ожидаете.
3. Они действительно должны поместить что-то вроде заметки или уведомления в официальные документы. Я потратил два дня на эту проблему.
4. Вы также можете использовать json_decode. Например, оберните ваш ответ в
json_decode($response, true);
это, и он вернет массив.5. Настоятельно рекомендую вам не использовать (string) $response->getBody(), поскольку он фактически не извлекает все данные. Он извлекает длину значения по умолчанию, поэтому может усечь фактическое значение. github.com/guzzle/guzzle/issues/1610
Ответ №2:
Если вы ожидаете возврата JSON, самый простой способ получить его:
$data = json_decode($response->getBody()); // returns an object
// OR
$data = json_decode($response->getBody(), true); // returns an array
json_decode()
автоматически приведет тело к string
, поэтому нет необходимости вызывать getContents()
.
Комментарии:
1.Этот простой ответ «решает» непосредственную проблему, но в нем отсутствует нюанс принятого ответа @Federkun. Причина, по которой это «просто работает» большую часть времени, заключается в том, что вызов
json_decode
неявно приводит тело ответа в виде строки. Сказав это, стоит понять принятый ответ, поскольку могут возникнуть проблемы с подходом к приведению строк, который не всегда извлекает все данные, как указано в комментарии @Shardj.2. Этот метод работает, но он приведет к ошибкам во время статического анализа
Ответ №3:
Для получения ответа в формате JSON :
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
$response = json_decode($res->getBody(),true);
$key_value = $response['key_name'];//access key