【问题标题】:How do I get the body of SENT data with Guzzle PHP?如何使用 Guzzle PHP 获取 SENT 数据的主体?
【发布时间】:2016-04-26 21:48:15
【问题描述】:

我在 PHP 中使用 Guzzle (v6.1.1) 向服务器发出 POST 请求。它工作正常。我正在添加一些日志记录功能来记录发送和接收的内容,但我不知道如何获取 Guzzle 发送到服务器的数据。我可以很好地得到响应,但是如何获取 sent 数据? (这将是 JSON 字符串。)

这是我的代码的相关部分:

$client = new GuzzleHttp\Client(['base_uri' => $serviceUrlPayments ]);
    try {
       $response = $client->request('POST', 'Charge', [
            'auth' => [$securenetId, $secureKey],
            'json' => [     "amount" => $amount,
                            "paymentVaultToken" => array(
                                    "customerId" => $customerId,
                                    "paymentMethodId" => $token,
                                    "publicKey" => $publicKey
                                    ),
                            "extendedInformation" => array(
                                    "typeOfGoods" => $typeOfGoods,
                                    "userDefinedFields" => $udfs,
                                    "notes" => $Notes
                                    ),
                            'developerApplication'=> $developerApplication 
            ]
    ]);

    } catch (ServerErrorResponseException $e) {
        echo (string) $e->getResponse()->getBody();
    }


    echo $response->getBody(); // THIS CORRECTLY SHOWS THE SERVER RESPONSE
    echo $client->getBody();           // This doesn't work
    echo $client->request->getBody();  // nor does this

任何帮助将不胜感激。我确实尝试在 Guzzle 源代码中查找类似于 getBody() 的函数来处理请求,但我不是 PHP 专家,所以我没有想出任何有用的东西。我也搜索了很多谷歌,但发现只有人在谈论从服务器返回响应,我对此没有任何问题。

【问题讨论】:

    标签: php http guzzle


    【解决方案1】:

    您可以通过创建Middleware 来完成这项工作。

    use GuzzleHttp\Client;
    use GuzzleHttp\HandlerStack;
    use GuzzleHttp\Middleware;
    use Psr\Http\Message\RequestInterface;
    
    $stack = HandlerStack::create();
    // my middleware
    $stack->push(Middleware::mapRequest(function (RequestInterface $request) {
        $contentsRequest = (string) $request->getBody();
        //var_dump($contentsRequest);
    
        return $request;
    }));
    
    $client = new Client([
        'base_uri' => 'http://www.example.com/api/',
        'handler' => $stack
    ]);
    
    $response = $client->request('POST', 'itemupdate', [
        'auth' => [$username, $password],
        'json' => [
            "key" => "value",
            "key2" => "value",
        ]
    ]);
    

    但是,这是在接收响应之前触发的。你可能想做这样的事情:

    $stack->push(function (callable $handler) {
        return function (RequestInterface $request, array $options) use ($handler) {
            return $handler($request, $options)->then(
                function ($response) use ($request) {
                    // work here
                    $contentsRequest = (string) $request->getBody();
                    //var_dump($contentsRequest);
                    return $response;
                }
            );
        };
    });
    

    【讨论】:

    • 这两种情况都会导致出现问题,我从服务器收到 404。
    • 我刚刚尝试过(guzzle 6.1),它对我有用。你能发布你的完整代码吗?
    • 我已经编辑了我的问题以显示实际代码,但变量赋值和不相关的代码除外。我尝试了您发布的内容,方法是在我的代码之前添加所有中间件代码,并在客户端对象创建命令中添加 'handler' => $stack
    • 默认 guzzle 使用four middleware。请参阅我的编辑。使用HandlerStack::create(); 创建堆栈。
    • 谢谢。大吃一惊,这种方式对于本应简单的任务来说太复杂了
    【解决方案2】:

    使用 Guzzle 6.2。

    过去几天我也一直在努力解决这个问题,同时尝试构建一种方法来审核与不同 API 的 HTTP 交互。在我的情况下,解决方案是简单地倒回请求正文。

    请求的正文实际上实现为stream。因此,当请求发送时,Guzzle 从流中读取。读取完整的流会将流的内部指针移动到末尾。因此,当您在发出请求后调用getContents() 时,内部指针已经位于流的末尾并且什么也不返回。

    解决方案?将指针倒回到开头并再次读取流。

    <?php
    // ...
    $body = $request->getBody();
    echo $body->getContents(); // -->nothing
    
    // Rewind the stream
    $body->rewind();
    echo $body->getContents(); // -->The request body :)
    

    【讨论】:

      【解决方案3】:

      我对Laravel 5.7的解决方案:

      MessageFormatter 可用于变量替换,请参阅:https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php

           $stack = HandlerStack::create();
              $stack->push(
                  Middleware::log(
                      Log::channel('single'),
                      new MessageFormatter('Req Body: {request}')
                  )
           );
      
          $client = new Client();
          $response = $client->request(
              'POST',
              'https://url.com/go',
              [
                  'headers' => [
                      "Content-Type" => "application/json",
                      'Authorization' => 'Bearer 123'
                  ],
                  'json' => $menu,
                  'handler' => $stack
              ]
          );
      

      【讨论】:

      • 对于 Laravel 5.3 用户:将 Log::channel('single') 替换为 Log::getMonolog()
      【解决方案4】:

      您可以通过执行复制请求创建的数据字符串

      $data = array(
          "key" => "value",
          "key2" => "value",
      ); 
      
      $response = $client->request('POST', 'itemupdate', [
          'auth' => [$username, $password],
          'json' => $data,
      ]);
      
      // ...
      
      echo json_encode($data);
      

      这会将您的数据输出为 JSON 字符串。

      http://php.net/manual/fr/function.json-encode.php的文档

      编辑

      Guzzle 有一个 Request 和一个 Response 类(以及许多其他类)。
      Request 实际上有一个 getQuery() 方法,该方法返回一个包含您的 data 的对象作为私有对象,与所有其他对象相同会员。
      您也无法访问它。

      这就是为什么我认为手动编码是更简单的解决方案。 如果你想知道 Guzzle 做了什么,它还有一个 Collection 类可以转换数据并在请求中发送。

      【讨论】:

      • 是的,我知道我可以这样做,但希望 Guzzle 中有一个内置函数可以让我获得请求,就像我可以通过 $response-&gt;getBody(); 获得响应一样/跨度>
      • 啊,是的,我试过 getQuery() 但它不起作用,所以如果它是私有的,那就是原因。感谢您为我澄清这一点。
      猜你喜欢
      • 2019-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-01
      • 2021-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多