Skip to content

[HttpClient] doc how to cancel a request + upload files #11668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 95 additions & 12 deletions components/http_client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ processed automatically when making the requests::
'body' => ['parameter1' => 'value1', '...'],

// using a closure to generate the uploaded data
'body' => function () {
'body' => function (int $size): string {
// ...
},

Expand All @@ -199,12 +199,39 @@ When uploading data with the ``POST`` method, if you don't define the
form data and adds the required
``'Content-Type: application/x-www-form-urlencoded'`` header for you.

When uploading JSON payloads, use the ``json`` option instead of ``body``. The
given content will be JSON-encoded automatically and the request will add the
``Content-Type: application/json`` automatically too::
When the ``body`` option is set as a closure, it will be called several times until
it returns the empty string, which signals the end of the body. Each time, the
closure should return a string smaller than the amount requested as argument.

$response = $httpClient->request('POST', 'https://...', [
'json' => ['param1' => 'value1', '...'],
A generator or any ``Traversable`` can also be used instead of a closure.

.. tip::

When uploading JSON payloads, use the ``json`` option instead of ``body``. The
given content will be JSON-encoded automatically and the request will add the
``Content-Type: application/json`` automatically too::

$response = $httpClient->request('POST', 'https://...', [
'json' => ['param1' => 'value1', '...'],
]);

$decodedPayload = $response->toArray();

To submit a form with file uploads, it is your responsibility to encode the body
according to the ``multipart/form-data`` content-type. The
:doc:`Symfony Mime </components/mime>` component makes it a few lines of code::

use Symfony\Component\Mime\Part\DataPart;
use Symfony\Component\Mime\Part\Multipart\FormDataPart;

$formFields = [
'regular_field' => 'some value',
'file_field' => DataPart::fromPath('/path/to/uploaded/file'),
];
$formData = new FormDataPart($formFields);
$client->request('POST', 'https://...', [
'headers' => $formData->getPreparedHeaders()->toArray(),
'body' => $formData->bodyToIterable(),
]);

Cookies
Expand Down Expand Up @@ -232,12 +259,47 @@ making a request. Use the ``max_redirects`` setting to configure this behavior
'max_redirects' => 0,
]);

HTTP Proxies
~~~~~~~~~~~~

By default, this component honors the standard environment variables that your
Operating System defines to direct the HTTP traffic through your local proxy.
This means there is usually nothing to configure to have the client work with
proxies, provided these env vars are properly configured.

You can still set or override these settings using the ``proxy`` and ``no_proxy``
options:

* ``proxy`` should be set to the ``http://...`` URL of the proxy to get through

* ``no_proxy`` disables the proxy for a comma-separated list of hosts that do not
require it to get reached.

Progress Callback
~~~~~~~~~~~~~~~~~

By providing a callable to the ``on_progress`` option, one can track
uploads/downloads as they complete. This callback is guaranteed to be called on
DNS resolution, on arrival of headers and on completion; additionally it is
called when new data is uploaded or downloaded and at least once per second::

$response = $httpClient->request('GET', 'https://...', [
'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
// $dlNow is the number of bytes downloaded so far
// $dlSize is the total size to be downloaded or -1 if it is unknown
// $info is what $response->getInfo() would return at this very time
},
];

Any exceptions thrown from the callback will be wrapped in an instance of
``TransportExceptionInterface`` and will abort the request.

Advanced Options
~~~~~~~~~~~~~~~~

The :class:`Symfony\\Contracts\\HttpClient\\HttpClientInterface` defines all the
options you might need to take full control of the way the request is performed,
including progress monitoring, DNS pre-resolution, timeout, SSL parameters, etc.
including DNS pre-resolution, SSL parameters, public key pinning, etc.

Processing Responses
--------------------
Expand All @@ -257,6 +319,9 @@ following methods::
// gets the response body as a string
$content = $response->getContent();

// cancels the request/response
$response->cancel();

// returns info coming from the transport layer, such as "response_headers",
// "redirect_count", "start_time", "redirect_url", etc.
$httpInfo = $response->getInfo();
Expand Down Expand Up @@ -285,10 +350,6 @@ response sequentially instead of waiting for the entire response::
$response = $httpClient->request('GET', $url, [
// optional: if you don't want to buffer the response in memory
'buffer' => false,
// optional: to display details about the response progress
'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
// ...
},
]);

// Responses are lazy: this code is executed as soon as headers are received
Expand All @@ -303,6 +364,28 @@ response sequentially instead of waiting for the entire response::
fwrite($fileHandler, $chunk->getContent());
}

Canceling Responses
~~~~~~~~~~~~~~~~~~~

To abort a request (e.g. because it didn't complete in due time, or you want to
fetch only the first bytes of the response, etc.), you can either use the
``cancel()`` method of ``ResponseInterface``::

$response->cancel()

Or throw an exception from a progress callback::

$response = $client->request('GET', 'https://...', [
'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
// ...

throw new \MyException();
},
]);

The exception will be wrapped in an instance of ``TransportExceptionInterface``
and will abort the request.

Handling Exceptions
~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -529,7 +612,7 @@ PSR-18 Compatibility
--------------------

This component uses and implements abstractions defined by the
``symfony/contracts`` package. It also implements the `PSR-18`_ (HTTP Client)
``symfony/http-client-contracts``. It also implements the `PSR-18`_ (HTTP Client)
specifications via the :class:`Symfony\\Component\\HttpClient\\Psr18Client`
class, which is an adapter to turn a Symfony ``HttpClientInterface`` into a
PSR-18 ``ClientInterface``.
Expand Down
2 changes: 1 addition & 1 deletion reference/configuration/framework.rst
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ This service can be configured using ``framework.http_client.default_options``:
http_client:
max_host_connections: 10
default_options:
headers: [{ 'X-Powered-By': 'ACME App' }]
headers: { 'X-Powered-By': 'ACME App' }
max_redirects: 7

.. _reference-http-client-scoped-clients:
Expand Down