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แต่มีข้อยกเว้นหากมีข้อผิดพลาดใช้ประโยชน์จากการจัดการที่ผิดพลาดอย่างเหมาะสม
Adrian Föder

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. สร้างMiddlewareซึ่งจะแทนที่ 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


นี่คือบางสิ่งที่ดี การใช้งาน Rest API Client ที่ฉันเพิ่งมารับงาน ฉันมีคำถามหนึ่งข้อเกี่ยวกับคำตอบของคุณ คลาส JsonAwareResponse ของคุณตั้งใจให้อยู่ภายใต้เนมสเปซ GuzzleHttp หรือไม่ ฉันลงเอยด้วยการสร้างคลาสนั้นภายใต้เนมสเปซของฉันเอง แต่อีกไม่นานฉันก็ค้นหารอบ ๆ codebase ของ GuzzleHttp ที่กำลังมองหาคลาสนั้น :) ขอบคุณอีกครั้ง!
floorz

อย่าใช้วิธีนี้เพราะมันแบ่ง PSR-7 MessageInterfaceอินเตอร์เฟซ ด้วย PSR-7 ไม่มีวิธีแก้ปัญหาทางกฎหมายในการแก้ไขส่วนต่อประสานนี้เพื่อส่งคืน JSON ที่ถอดรหัสจากgetBody()วิธี
Sergey Nevmerzhitsky

3

$responseเป็นตัวอย่างของ ResponseInterfacePSR-7 สำหรับรายละเอียดเพิ่มเติมดู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šekMaša
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.