📜  如何在PHP发出异步 HTTP 请求?

📅  最后修改于: 2021-11-08 06:20:09             🧑  作者: Mango

异步 HTTP 请求帮助我们在不同线程中使用非阻塞输入或输出处理 HTTP 请求。有些人将其称为 COMET 能力。异步 HTTP 请求的主要用途是当客户端向服务器请求延迟响应时。一个常见的例子是 AJAX 聊天客户端,我们从客户端和服务器推送或拉取。这些场景会在服务器的套接字上阻塞客户端长时间等待新消息。

PHP同步处理请求。这意味着每一行代码都以脚本的同步方式执行。从一行获取结果后,它执行下一行或等待结果,然后跳转到下一行代码的执行。在某些情况下,我们应该向 URL 发出请求并且它们不相互依赖。在这种情况下,我们不想等待一个请求的结果来执行其他请求。因此,我们发出异步请求。

Guzzle 6: Guzzle 是一个PHP HTTP 客户端,帮助发送 HTTP 请求。这些方法可用于发送异步 HTTP 请求。

  • 请求异步,
  • 发送异步,
  • 获取异步,
  • 头异步,
  • 放置异步,
  • 异步后,
  • 删除异步,
  • 补丁异步

下载 Guzzle PHP包。可以通过 composer 安装。

php composer.phar require guzzlehttp/guzzle:~6.0

或者

composer require guzzlehttp/guzzle:~6.0

请在代码的脚本部分包含“自动加载”文件,以便它加载所有类和方法。

PHP
getAsync('http://localhost')
            ->then(function ($response)
    { echo '10'; }),
     
    $client->getAsync('http://www.google.com')
            ->then(function ($response)
    { echo '20'; }),
      
    $client->getAsync('http://localhost')
            ->then(function ($response)
    { echo '30'; }),
      
    $client->getAsync('http://localhost')
            ->then(function ($response)
    { echo '40'; }),
      
    $client->getAsync('http://localhost')
            ->then(function ($response)
    { echo '50'; }),
      
    $client->getAsync('http://localhost')
            ->then(function ($response)
    { echo '60'; }),
      
    $client->getAsync('http://localhost')
            ->then(function ($response)
   { echo '70'; }),
];
  
$results = GuzzleHttp\Promise\unwrap($promises);
  
// Please wait for a while to complete 
// the requests(some of them may fail)
$results = GuzzleHttp\Promise\settle(
        $promises)->wait();
          
print "finish/over." . PHP_EOL;
?>


PHP
getAsync(
   'https://api.demo.com/v1/users?username='
        . $user);        
    }
})();
   
$eachPromise = new EachPromise($promises, [
      
    // Number of concurrency
    'concurrency' => 4,
    'fulfilled' => function (Response $response) {
        if ($response->getStatusCode() == 200) {
            $user = json_decode(
                $response->getBody(), true);
              
            // processing response of the user
        }
    },
      
    'rejected' => function ($reason) {
    // handle promise rejected 
    }
]);
   
$eachPromise->promise()->wait();
?>


在上面的代码中,包含了“自动加载”文件,然后创建了 Guzzle Http 客户端对象,该对象存储在“客户端”变量中,并且对于每个 Http 请求,将getAsync()方法与 URL 一起使用。
获得第一个响应的请求将打印数字。请求的顺序无关紧要。

使用 Promise 的异步 HTTP 请求:异步操作的单个结果代表一个Promise 。异步请求用于 HTTP 操作的非阻塞。当异步 HTTP 请求发送承诺时,它会被返回。

使用 HTTPlug 执行请求:

$request = $messageFactory->createRequest(
    'GET', 'http://php-http.org');
$promise = $client->sendAsyncRequest($request);
echo  'Non-blocking!';

等待:从上面返回的“promise”,实现了http\Promise\Promise 。在这个时间点上,响应尚不可知。等待那个回应的到来。

try {
  $response = $promise->wait();
} catch (\Exception $exception) {
  echo $exception->getMessage();
}  

然后:我们可以异步执行步骤,而不是等待。使用两个参数调用then方法。

  1. 如果请求成功,将执行的一个回调。
  2. 如果请求导致错误,将执行的回调。
// Success Callback
function (ResponseInterface $response) {
    
    echo 'New response!';

    // Write status code to the log file
    file_put_contents('responses.log', 
        $response->getStatusCode() . "\n", FILE_APPEND);
    return $response;
},

// Failure Callback
function (\Exception $exception) {
    echo 'We have a problem';
    throw $exception;
}

Promise 中的并发并发意味着多个计算同时发生。当我们同时处理很多请求时很好。对于并发,我们必须使用“EachPromise”类和yield生成器,最后在程序末尾添加wait()

PHP

getAsync(
   'https://api.demo.com/v1/users?username='
        . $user);        
    }
})();
   
$eachPromise = new EachPromise($promises, [
      
    // Number of concurrency
    'concurrency' => 4,
    'fulfilled' => function (Response $response) {
        if ($response->getStatusCode() == 200) {
            $user = json_decode(
                $response->getBody(), true);
              
            // processing response of the user
        }
    },
      
    'rejected' => function ($reason) {
    // handle promise rejected 
    }
]);
   
$eachPromise->promise()->wait();
?>

构建多线程cURL请求:一般我们可以处理多个请求。首先,我们触发第一个并处理响应,然后是第二个和第三个,依此类推。但是,此过程缓慢且耗时。但是 cURL 提供curl_multi_*函数来处理任何 asnyc 请求。

$running = null;
$mh = curl_multi_init();

$ch1 = curl_init();
curl_setopt($ch1, CURLOPT_URL, 'https://endpoint.com');

// Other curl options....
curl_multi_add_handle($mh, $ch1);

$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, 'https://endpoint.com');

// Other curl options....  
curl_multi_add_handle($mh, $ch2);

do {
   curl_multi_exec($mh, $running);
   curl_multi_select($mh);
} while ($running > 0);

$r1 = curl_multi_getcontent($ch1);
$r2 = curl_multi_getcontent($ch2);
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);

响应被收集在“r1”和“r2”变量中。借助这些 cURL 函数,我们可以并行触发请求以节省时间并更快地处理响应。