Yii2中如何从异步GuzzleHttp请求返回响应及处理异常?
Looks like you've hit two key issues with your Guzzle async implementation—let's break them down and fix this step by step.
First: Why you're getting a Response object instead of your array
When you call $promise->then(), it returns a new Promise that wraps your transformed response/error array. But you're not assigning this new Promise back to $promise, so when you call $promise->wait(), you're still waiting on the original Promise that resolves to the raw Response object. That's exactly why you're seeing the "Cannot use object of type GuzzleHttp\Psr7\Response as array" error.
Second: Unhandled edge case in error handling
If the request fails entirely (e.g., no connection, DNS failure), $e->getResponse() will return null. Trying to call getStatusCode() on that will throw another fatal error—we need to handle this scenario gracefully.
Third: A small variable typo in sendAsyncRequest
You're using $client->utm_source to build $url_params, but $client isn't a parameter of this method. You should be using the $params['utm_source'] that's passed into the method instead.
Here's the fixed version of your Logger class with all these issues addressed:
use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\Psr7\Request; use GuzzleHttp\Exception\RequestException; use Psr\Http\Message\ResponseInterface; class Logger { public function processAsyncRequest($client) { $response = $this->sendAsyncRequest($client->phone, ['utm_source' => $client->utm_source]); $this->logResponse($client, $response); } public function sendAsyncRequest($phone, $params) { // Fix the variable typo here to use the passed-in params $url_params = http_build_query(['utm_source' => $params['utm_source']]); $guzzleClient = new GuzzleClient(); $headers = [ 'Content-Type' => 'application/json', 'Authorization' => 'Basic xxxxxxxxxx', ]; $request = new Request('POST', 'url' . $phone . '/tokens/?' . $url_params, $headers); $promise = $guzzleClient->sendAsync($request); // Assign the transformed Promise back to $promise $promise = $promise->then( function (ResponseInterface $response) { return [ 'code' => $response->getStatusCode(), 'body' => $response->getBody()->__toString(), ]; }, function(RequestException $e) { // Handle cases where no response was received at all $statusCode = $e->getResponse() ? $e->getResponse()->getStatusCode() : 0; $body = $e->getResponse() ? $e->getResponse()->getBody()->__toString() : $e->getMessage(); return [ 'code' => $statusCode, 'body' => $body, ]; } ); // Now wait() will resolve to our custom array instead of the raw Response $res = $promise->wait(); return $res; } public function logResponse($client, $data) { $log = new Log(); $log->client_id = $client->id; // Optional: Log the full actual URL for debugging purposes $log->url = 'url' . $client->phone . '/tokens/?' . http_build_query(['utm_source' => $client->utm_source]); $log->response = $data['code'] . ', ' . $data['body']; $log->comment = 'reg'; return $log->save(); } }
Key Fixes Explained
- Promise Chaining: By assigning
$promise = $promise->then(...), we ensure thatwait()resolves to our transformed array instead of the raw Response object. - Safe Error Handling: We added a check for
$e->getResponse()before accessing its methods, preventing fatal errors when the request can't reach the server. - Variable Typo Fix: Swapped
$client->utm_sourcefor$params['utm_source']to match the method's input parameters. - Optional Full URL Logging: Updated
logResponseto log the complete URL used (you can remove this if not needed, but it's useful for debugging failed requests).
内容的提问来源于stack exchange,提问作者Dmitry

