Жрет 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']);

Или есть помощник или что-то в этом роде?

рэп-2-х
источник

Ответы:

292

Я использую json_decode($response->getBody())сейчас вместо $response->json().

Я подозреваю, что это может быть жертвой соблюдения PSR-7.

meriial
источник
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)

Вместо другого комментария, если вы хотите, чтобы он работал точно так же, как и раньше, чтобы получить массивы вместо объектов.

dmyers
источник
29

Я использую, $response->getBody()->getContents()чтобы получить JSON из ответа. Жрет версию 6.3.0.

jusep
источник
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()читает остальную часть потока, а повторный вызов ничего не возвращает, потому что поток уже находится в конце. Вам придется перемотать поток между этими вызовами.
simPod
источник
1

Добавление ->getContents()не возвращает ответ jSON, а возвращается как текст.

Вы можете просто использовать json_decode

Мох
источник
Возвращает JSON как текст, а не HTML.
Франтишек Маша