Petunjuk 6: tidak ada lagi metode json () untuk tanggapan

172

Sebelumnya di Guzzle 5.3:

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

Saya bisa dengan mudah mendapatkan array PHP dari respons JSON. Sekarang dalam Guzzle 6, saya tidak tahu bagaimana melakukannya. Sepertinya tidak ada json()metode lagi. Saya (cepat) membaca dokumen dari versi terbaru dan tidak menemukan apa pun tentang respons JSON. Saya rasa saya melewatkan sesuatu, mungkin ada konsep baru yang tidak saya mengerti (atau mungkin saya tidak membaca dengan benar).

Apakah ini (di bawah) cara baru satu-satunya cara?

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

Atau ada penolong atau semacamnya?

rap-2-h
sumber

Jawaban:

292

Saya menggunakan json_decode($response->getBody())sekarang, bukan $response->json().

Saya menduga ini mungkin korban kepatuhan PSR-7.

meriial
sumber
4
Tidak ada dalam dokumentasi yang membuat ini eksplisit tetapi tampaknya mereka telah menghapus $response->json()helper.
penjepit kertas
60
Jika Anda mengharapkan respons larik seperti cara kerja aslinya ->json(), gunakan json_decode($response->getBody(), true)sebagai gantinya untuk mendapatkan larik alih-alih stdObject
Jay El-Kaake
14
Dengan menggunakan strict_types, saya harus melemparkan tubuh respons Guzzle ke string sebelum mendekodekannya:json_decode((string) $response->getBody(), true)
Yoan Tournade
Saya selalu suka menggunakan \GuzzleHttp\json_decode(atau \GuzzleHttp\Utils::jsonDecodetergantung pada versi Guzzle yang Anda gunakan ) yang memiliki tanda tangan yang kompatibel \json_decode, tetapi melemparkan pengecualian jika ada kesalahan, meningkatkan penanganan kesalahan yang tepat.
Adrian Föder
112

Anda beralih ke:

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

Alih-alih komentar lain jika Anda ingin bekerja persis seperti sebelumnya untuk mendapatkan array, bukan objek.

dmyers
sumber
29

Saya menggunakan $response->getBody()->getContents()untuk mendapatkan JSON dari respons. Buang versi 6.3.0.

jusep
sumber
6
Memanggil getContents()di badan respons akan mengosongkan aliran dan panggilan berikutnya getContents()akan kembali kosong. Jika Anda ingin mendapatkan tubuh sebagai string gunakan:strval($response->getBody())
JVitela
1
Saya berharap komentar ini lebih tinggi. Saya sedang login respons saya menggunakan getContent dan ketika saya pergi untuk mem-parsing baris kemudian, array saya kosong. Biaya saya berjam-jam. Terima kasih!
Colin
14

Jika kalian masih tertarik, ini solusi saya berdasarkan fitur middleware Guzzle :

  1. Buat JsonAwaraResponseyang akan mendekode respons JSON dengan Content-Typetajuk HTTP, jika tidak - itu akan bertindak sebagai Respons Gerobak standar:

    <?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. Buat Middleware yang akan menggantikan respons Guzzle PSR-7 dengan implementasi Respons di atas:

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

Setelah ini untuk mengambil JSON sebagai array asli PHP, gunakan Guzzle seperti biasa:

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

Diuji dengan guzzlehttp / guzzle 6.3.3

andrew
sumber
Ini beberapa hal bagus. Menggunakan tugas Klien API Istirahat yang baru saja saya ambil di tempat kerja. Saya punya satu pertanyaan tentang jawaban Anda. Apakah kelas JsonAwareResponse Anda dimaksudkan untuk berada di bawah namespace GuzzleHttp? Saya akhirnya hanya menciptakan kelas itu di bawah namespace saya sendiri, tetapi untuk sesaat saya mencari di sekitar basis kode GuzzleHttp mencari kelas itu. :) Terima kasih lagi!
floorz
Jangan gunakan solusi ini karena itu merusak antarmuka PSR-7 MessageInterface. Dengan PSR-7 tidak ada solusi hukum untuk menambal antarmuka ini untuk mengembalikan JSON yang didekodekan dari getBody()metode.
Sergey Nevmerzhitsky
3

$responseadalah turunan dari PSR-7 ResponseInterface. Untuk perincian lebih lanjut, lihat https://www.php-fig.org/psr/psr-7/#3-interfaces

getBody()pengembalian StreamInterface:

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

StreamInterfacemengimplementasikan __toString()yang tidak

Membaca semua data dari aliran menjadi string, dari awal hingga akhir.

Karenanya, untuk membaca body sebagai string, Anda harus mengubahnya menjadi string:

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


Gotcha

  1. json_decode($response->getBody()bukan solusi terbaik karena secara ajaib memasukkan aliran ke string untuk Anda. json_decode()membutuhkan string sebagai argumen pertama.
  2. Jangan gunakan $response->getBody()->getContents()kecuali Anda tahu apa yang Anda lakukan. Jika Anda membaca dokumentasi untuk getContents(), ia mengatakan: Returns the remaining contents in a string. Oleh karena itu, panggilan getContents()membaca sisa aliran dan memanggilnya kembali tidak menghasilkan apa-apa karena aliran sudah di akhir. Anda harus memutar ulang aliran di antara panggilan-panggilan itu.
simPod
sumber
1

Menambahkan ->getContents()tidak mengembalikan respons JSON, melainkan mengembalikan sebagai teks.

Anda cukup menggunakan json_decode

Moh
sumber
Ini mengembalikan JSON sebagai teks, bukan HTML.
František Maša