Жрет 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
— Джей Эль-Кааке,

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 из ответа. Жрет версию 6.3.0.


6
Вызов getContents()в теле ответа очистит поток, а следующий вызов getContents()вернет пустой. Если вы хотите получить тело в виде строки, используйте:strval($response->getBody())
— JVitela

1
Я хотел бы, чтобы этот комментарий был выше. Я регистрировал свой ответ, используя getContent, и когда я пошел анализировать строку позже, мой массив был пуст. Стоило мне часов. Спасибо!
— Colin

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 на приведенную выше реализацию Response:

    <?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


Это хороший материал. Использование в клиентской задаче Rest 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.
— Франтишек Маша
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.