Guzzle 6: немає більше методу json () для відповідей


172

Раніше в Guzzle 5.3:

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

Я міг легко отримати масив PHP з відповіді JSON. Зараз у Guzzle 6 я не знаю, як це зробити. Здається, немає жодного json()методу. Я (швидко) прочитав документ з останньої версії і нічого не знайшов про відповіді JSON. Я думаю, що я щось пропустив, можливо, є нова концепція, яку я не розумію (або, можливо, я не прочитав правильно).

Це єдиний шлях (нижче) новий спосіб?

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

Або є помічник чи щось подібне?

Відповіді:


292

Я використовую json_decode($response->getBody())зараз замість $response->json().

Я підозрюю, що це може бути випадковістю дотримання PSR-7.


4
Нічого в документації, що не робить це явним, але, здається, вони припинили $response->json()допомогу.
скріпка

60
Якщо ви очікуєте відповіді масиву, наприклад, як ->json()працював оригінал , json_decode($response->getBody(), true)замість stdObject отримайте масив
Jay El-Kaake

14
Використовуючи strict_types, мені потрібно було передати тіло відповіді Guzzle на рядок, перш ніж розшифрувати його:json_decode((string) $response->getBody(), true)
Yoan Tournade

Мені завжди подобалося використовувати \GuzzleHttp\json_decode(або \GuzzleHttp\Utils::jsonDecodeзалежно від версії Guzzle, на якій ви працюєте), яка має сумісний підпис \json_decode, але видає виняток, якщо є помилка, використовуючи правильне поводження з помилками.
Адріан Федер

112

Ви переходите до:

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

Замість іншого коментаря, якщо ви хочете, щоб він працював точно так, як раніше, щоб отримати масиви замість об'єктів.


29

Я використовую $response->getBody()->getContents()для отримання JSON від відповіді. Версія Guzzle 6.3.0.


6
Виклик getContents()у тілі відповіді сповільнить потік, а наступний дзвінок до getContents()- повернеться порожнім. Якщо ви хочете отримати тіло як строкове використання:strval($response->getBody())
JVitela,

1
Я б хотів, щоб цей коментар був вищим. Я реєстрував свою відповідь за допомогою getContent, і коли я пішов розбирати рядок пізніше, мій масив був порожнім. Коштують мене години. Дякую!
Колін

14

Якщо ви, хлопці, все ще зацікавлені, ось моє рішення, засноване на програмному забезпеченні Guzzle елемент:

  1. Створіть, JsonAwaraResponseщо розшифрує JSON-відповідь Content-Typeзаголовком HTTP, якщо ні - він буде діяти як стандартна реакція Guzzle:

    <?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. Створіть середнє програмне забезпечення, яке замінить відповіді Guzzle PSR-7 на вищевказану реалізацію відповідей:

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

Після цього для отримання JSON як PHP-матриці використовуйте Guzzle як завжди:

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

Випробуваний за допомогою guzzlehttp / guzzle 6.3.3


Це хороший матеріал. Використання в завданні клієнта API відпочинку, яке я щойно взяв на роботу. У мене є одне питання щодо вашої відповіді. Чи повинен ваш клас JsonAwareResponse знаходитися під простором імен GuzzleHttp? Я в кінцевому підсумку просто створив цей клас під власним простором імен, але на секунду я шукав навколо кодової бази GuzzleHttp, шукаючи цього класу. :) Знову дякую!
floorz

Не використовуйте це рішення, оскільки воно порушує інтерфейс PSR-7 MessageInterface. З PSR-7 немає законного рішення виправити цей інтерфейс, щоб повернути декодований JSON з getBody()методу.
Сергій Невмержицький

3

$responseє примірником PSR-7 ResponseInterface. Більш детально див. Https://www.php-fig.org/psr/psr-7/#3-interfaces

getBody() повертає StreamInterface :

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

StreamInterfaceреалізує, __toString()що робить

Читає всі дані з потоку в рядок, від початку до кінця.

Тому, щоб прочитати тіло як рядок, ви повинні накинути його на рядок:

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


Gotchas

  1. json_decode($response->getBody()не найкраще рішення, оскільки воно магічно перекидає потік у рядок для вас. json_decode()вимагає рядок як 1-й аргумент.
  2. Не використовуйте, $response->getBody()->getContents()якщо ви не знаєте, що робите. Якщо ви читаєте документацію getContents(), він говорить: Returns the remaining contents in a string. Тому дзвінок getContents()зчитує решту потоку і знову викликає нічого, тому що потік вже в кінці. Вам доведеться перемотати поток між цими дзвінками.

1

Додавання ->getContents()не повертає відповідь jSON, натомість повертається як текст.

Ви можете просто використовувати json_decode


Він повертає JSON як текст, а не HTML.
František Maša
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.