How to make asynchronous HTTP requests in PHP ?

Asynchronous HTTP request helps us to process HTTP requests using non-blocking input or output, in different threads. Some refer to it as COMET capabilities. The main use of Asynchronous HTTP requests is when the client is requesting the server for a late response. A common example is an AJAX chat client where we push or pull from both the client and the server. These scenarios block the client for quiet a long time on the server’s socket waiting for a new message. 

PHP serves requests synchronously. It means that each line of code executes in the synchronous manner of the script. After getting the result from one line it executes next line or wait for the result before jumping to the execution of the next line of code. There are cases where we are supposed to make requests to URLs and they do not rely on each other. In this scenario we do not want to wait for the result from one request to execute other requests. Therefore, we make asynchronous requests.

Guzzle 6: Guzzle is a PHP HTTP client helps to send the HTTP requests.These methods can be used to send the asynchronous HTTP requests.

  • RequestAsync,
  • SendAsync,
  • GetAsync,
  • HeadAsync,
  • PutAsync,
  • PostAsync,
  • DeleteAsync,
  • patchAsync

Download Guzzle php package.Can be installed through composer.

php composer.phar require guzzlehttp/guzzle:~6.0

or



composer require guzzlehttp/guzzle:~6.0

Please include the “autoload” file in the script part of the code so that it loads all the classes and methods.

PHP

filter_none

edit
close

play_arrow

link
brightness_4
code

<?php
  
require_once(__DIR__ . '/vendor/autoload.php');
$client = new GuzzleHttp\Client();
  
$promises = [
    $client->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;
?>

chevron_right


In the above code, the “autoload” file is included, and then the Guzzle Http client object is created which is stored in the “client” variable and for each Http request getAsync() method is used with the URL.
The request getting the first response will print the number. The order of the request will not matter.

Asynchronous HTTP requests using Promise: A single result of an asynchronous operation represents a Promise. Asynchronous requests are used in the non-blocking of the HTTP operations. When asynchronous HTTP requests send a promise, it gets returned.

Execute a request using HTTPlug:

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

Wait: The “promise” which is returned from the above, implements http\Promise\Promise. The response is not known yet during this point of time. Wait for that response to arrive.

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

Then: Instead of waiting, we can perform steps asynchronously. Call the then method with two arguments.

  1. One callback that will be executed if the request turns out to be successful.
  2. Callback that will be executed if the request results in an error.
  
// 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;
}

Concurrency in Promise: Concurrency means multiple computations taking place at the same time. It is good when we deal with a lot of request at the same time. For concurrency, we must use “EachPromise” class and yield generator and at last add wait() to the end of the program.

PHP

filter_none

edit
close

play_arrow

link
brightness_4
code

<?php
  
use GuzzleHttp\Promise\EachPromise;
use GuzzleHttp\Psr7\Response;
   
$users = ['one', 'two', 'three'];
   
$promises = (function () use ($users) {
    foreach ($users as $user) {
          
        // Using generator
        yield $this->getAsync(
        . $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();
?>

chevron_right


Building a multi-thread cURL request: Generally, we can handle multiple requests. First, we trigger the first one and process the response, then the second and third, and so on. But, this process is slow and time-consuming. But cURL offers the curl_multi_* functions to handle any asnyc requests.

$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);

The responses get collected in the “r1” and “r2” variables. With the help of these cURL functions, we can trigger requests parallel to save time and process the responses quicker.

full-stack-img




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.