Http
Event-driven, streaming HTTP client and server implementation for ReactPHP.
Install / Use
/learn @reactphp/HttpREADME
HTTP
Event-driven, streaming HTTP client and server implementation for ReactPHP.
Development version: This branch contains the code for the upcoming v3 release. For the code of the current stable v1 release, check out the
1.xbranch.The upcoming v3 release will be the way forward for this package. However, we will still actively support v1 for those not yet on the latest version. See also installation instructions for more details.
This HTTP library provides re-usable implementations for an HTTP client and
server based on ReactPHP's Socket and
EventLoop components.
Its client component allows you to send any number of async HTTP/HTTPS requests
concurrently.
Its server component allows you to build plaintext HTTP and secure HTTPS servers
that accept incoming HTTP requests from HTTP clients (such as web browsers).
This library provides async, streaming means for all of this, so you can handle
multiple concurrent HTTP requests without blocking.
Table of contents
- Quickstart example
- Client Usage
- Server Usage
- API
- Install
- Tests
- License
Quickstart example
Once installed, you can use the following code to access an HTTP web server and send some simple HTTP GET requests:
<?php
require __DIR__ . '/vendor/autoload.php';
$client = new React\Http\Browser();
$client->get('http://www.google.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
var_dump($response->getHeaders(), (string)$response->getBody());
}, function (Exception $e) {
echo 'Error: ' . $e->getMessage() . PHP_EOL;
});
This is an HTTP server which responds with Hello World! to every request.
<?php
require __DIR__ . '/vendor/autoload.php';
$http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
return React\Http\Message\Response::plaintext(
"Hello World!\n"
);
});
$socket = new React\Socket\SocketServer('127.0.0.1:8080');
$http->listen($socket);
See also the examples.
Client Usage
Request methods
Most importantly, this project provides a Browser object that
offers several methods that resemble the HTTP protocol methods:
$browser->get($url, array $headers = []);
$browser->head($url, array $headers = []);
$browser->post($url, array $headers = [], string|ReadableStreamInterface $body = '');
$browser->delete($url, array $headers = [], string|ReadableStreamInterface $body = '');
$browser->put($url, array $headers = [], string|ReadableStreamInterface $body = '');
$browser->patch($url, array $headers = [], string|ReadableStreamInterface $body = '');
Each of these methods requires a $url and some optional parameters to send an
HTTP request. Each of these method names matches the respective HTTP request
method, for example the get() method sends an HTTP GET request.
You can optionally pass an associative array of additional $headers that will be
sent with this HTTP request. Additionally, each method will automatically add a
matching Content-Length request header if an outgoing request body is given and its
size is known and non-empty. For an empty request body, if will only include a
Content-Length: 0 request header if the request method usually expects a request
body (only applies to POST, PUT and PATCH HTTP request methods).
If you're using a streaming request body, it will default
to using Transfer-Encoding: chunked unless you explicitly pass in a matching Content-Length
request header. See also streaming request for more details.
By default, all of the above methods default to sending requests using the
HTTP/1.1 protocol version. If you want to explicitly use the legacy HTTP/1.0
protocol version, you can use the withProtocolVersion()
method. If you want to use any other or even custom HTTP request method, you can
use the request() method.
Each of the above methods supports async operation and either fulfills with a
PSR-7 ResponseInterface
or rejects with an Exception.
Please see the following chapter about promises for more details.
Promises
Sending requests is async (non-blocking), so you can actually send multiple
requests in parallel.
The Browser will respond to each request with a
PSR-7 ResponseInterface
message, the order is not guaranteed.
Sending requests uses a Promise-based
interface that makes it easy to react to when an HTTP request is completed
(i.e. either successfully fulfilled or rejected with an error):
$browser->get($url)->then(
function (Psr\Http\Message\ResponseInterface $response) {
var_dump('Response received', $response);
},
function (Exception $e) {
echo 'Error: ' . $e->getMessage() . PHP_EOL;
}
);
If this looks strange to you, you can also use the more traditional blocking API.
Keep in mind that resolving the Promise with the full response message means the whole response body has to be kept in memory. This is easy to get started and works reasonably well for smaller responses (such as common HTML pages or RESTful or JSON API requests).
You may also want to look into the streaming API:
- If you're dealing with lots of concurrent requests (100+) or
- If you want to process individual data chunks as they happen (without having to wait for the full response body) or
- If you're expecting a big response body size (1 MiB or more, for example when downloading binary files) or
- If you're unsure about the response body size (better be safe than sorry when accessing arbitrary remote HTTP endpoints and the response body size is unknown in advance).
Cancellation
The returned Promise is implemented in such a way that it can be cancelled when it is still pending. Cancelling a pending promise will reject its value with an Exception and clean up any underlying resources.
$promise = $browser->get($url);
Loop::addTimer(2.0, function () use ($promise) {
$promise->cancel();
});
Timeouts
This library uses a very efficient HTTP implementation, so most HTTP requests
should usually be completed in mere milliseconds. However, when sending HTTP
requests over an unreliable network (the internet), there are a number of things
that can go wrong and may cause the request to fail after a time. As such, this
library respects PHP's default_socket_timeout settin
