Guzzle 6: больше нет метода json () для ответов

Ранее в 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']);

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


person rap-2-h    schedule 29.05.2015    source источник


Ответы (6)


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

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

person meriial    schedule 29.05.2015
comment
В документации нет ничего, что делало бы это явным, но похоже, что они отказались от помощника $response->json(). - person paperclip; 08.06.2015
comment
Если вы ожидаете ответа массива, подобного тому, как работал исходный ->json(), используйте вместо этого json_decode($response->getBody(), true), чтобы получить массив вместо stdObject. - person Jay El-Kaake; 23.12.2015
comment
Используя strict_types, мне нужно было преобразовать тело ответа Guzzle в строку перед его декодированием: json_decode((string) $response->getBody(), true) - person Yoan Tournade; 23.03.2018
comment
Мне всегда нравилось использовать \GuzzleHttp\json_decode (или \GuzzleHttp\Utils::jsonDecode в зависимости от используемой вами версии Guzzle), которая имеет совместимую подпись с \json_decode, но выдает исключение в случае ошибки, используя правильную обработку ошибок. - person Adrian Föder; 18.07.2020
comment
В strict_types вы можете преобразовать в string, как предлагает @YoanTournade, или вместо этого использовать $response->getBody()->getContents(), который возвращает строку. - person The Unknown Dev; 09.11.2020

Вы переключаетесь на:

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

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

person dmyers    schedule 10.11.2015

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

person jusep    schedule 21.03.2018
comment
Вызов getContents() в теле ответа очистит поток, а следующий вызов getContents() вернет пустой. Если вы хотите получить тело в виде строки, используйте: strval($response->getBody()) - person JVitela; 01.08.2018
comment
Хотелось бы, чтобы этот комментарий был выше. Я регистрировал свой ответ с помощью getContent, и когда позже я пошел анализировать строку, мой массив был пуст. Стоило мне часов. Спасибо! - person Colin; 13.06.2019

Если вам все еще интересно, вот мой обходной путь, основанный на промежуточном программном обеспечении 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

person andrew    schedule 23.11.2018
comment
Это хороший материал. Использование в задаче Rest API Client, которую я только что взял на работе. Однако у меня есть один вопрос по поводу вашего ответа. Был ли ваш класс JsonAwareResponse предназначен для размещения в пространстве имен GuzzleHttp? Я закончил тем, что просто создал этот класс в своем собственном пространстве имен, но в течение секунды я искал кодовую базу GuzzleHttp в поисках этого класса. :) Спасибо еще раз! - person sdaugherty; 19.08.2019
comment
Не используйте это решение, потому что оно нарушает интерфейс PSR-7 MessageInterface. В PSR-7 нет законного решения для исправления этого интерфейса для возврата декодированного JSON из метода getBody(). - person Sergey Nevmerzhitsky; 29.05.2020

$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()


Попался

  1. json_decode($response->getBody() - не лучшее решение, так как оно волшебным образом переводит поток в строку за вас. json_decode() требует строки в качестве первого аргумента.
  2. Не используйте $response->getBody()->getContents(), если не знаете, что делаете. Если вы читали документацию для getContents(), там написано: Returns the remaining contents in a string. Следовательно, вызов getContents() читает остальную часть потока, а повторный вызов ничего не возвращает, потому что поток уже находится в конце. Вам придется перематывать поток между этими вызовами.
person simPod    schedule 24.11.2019

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

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

person Moh    schedule 28.06.2018
comment
Он возвращает JSON в виде текста, а не HTML. - person František Maša; 13.07.2018