Skip to content

Commit 3d0644f

Browse files
committed
Merge branch '4.4'
* 4.4: [HttpClient] doc how to cancel a request + upload files
2 parents 390bb5b + 41dd55e commit 3d0644f

File tree

2 files changed

+96
-26
lines changed

2 files changed

+96
-26
lines changed

components/http_client.rst

Lines changed: 95 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ processed automatically when making the requests::
182182
'body' => ['parameter1' => 'value1', '...'],
183183

184184
// using a closure to generate the uploaded data
185-
'body' => function () {
185+
'body' => function (int $size): string {
186186
// ...
187187
},
188188

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

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

202-
$response = $httpClient->request('POST', 'https://...', [
203-
'json' => ['param1' => 'value1', '...'],
202+
A generator or any ``Traversable`` can also be used instead of a closure.
203+
204+
.. tip::
205+
206+
When uploading JSON payloads, use the ``json`` option instead of ``body``. The
207+
given content will be JSON-encoded automatically and the request will add the
208+
``Content-Type: application/json`` automatically too::
209+
210+
$response = $httpClient->request('POST', 'https://...', [
211+
'json' => ['param1' => 'value1', '...'],
212+
]);
213+
214+
$decodedPayload = $response->toArray();
215+
216+
To submit a form with file uploads, it is your responsibility to encode the body
217+
according to the ``multipart/form-data`` content-type. The
218+
:doc:`Symfony Mime </components/mime>` component makes it a few lines of code::
219+
220+
use Symfony\Component\Mime\Part\DataPart;
221+
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
222+
223+
$formFields = [
224+
'regular_field' => 'some value',
225+
'file_field' => DataPart::fromPath('/path/to/uploaded/file'),
226+
];
227+
$formData = new FormDataPart($formFields);
228+
$client->request('POST', 'https://...', [
229+
'headers' => $formData->getPreparedHeaders()->toArray(),
230+
'body' => $formData->bodyToIterable(),
204231
]);
205232

206233
Cookies
@@ -228,12 +255,47 @@ making a request. Use the ``max_redirects`` setting to configure this behavior
228255
'max_redirects' => 0,
229256
]);
230257

258+
HTTP Proxies
259+
~~~~~~~~~~~~
260+
261+
By default, this component honors the standard environment variables that your
262+
Operating System defines to direct the HTTP traffic through your local proxy.
263+
This means there is usually nothing to configure to have the client work with
264+
proxies, provided these env vars are properly configured.
265+
266+
You can still set or override these settings using the ``proxy`` and ``no_proxy``
267+
options:
268+
269+
* ``proxy`` should be set to the ``http://...`` URL of the proxy to get through
270+
271+
* ``no_proxy`` disables the proxy for a comma-separated list of hosts that do not
272+
require it to get reached.
273+
274+
Progress Callback
275+
~~~~~~~~~~~~~~~~~
276+
277+
By providing a callable to the ``on_progress`` option, one can track
278+
uploads/downloads as they complete. This callback is guaranteed to be called on
279+
DNS resolution, on arrival of headers and on completion; additionally it is
280+
called when new data is uploaded or downloaded and at least once per second::
281+
282+
$response = $httpClient->request('GET', 'https://...', [
283+
'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
284+
// $dlNow is the number of bytes downloaded so far
285+
// $dlSize is the total size to be downloaded or -1 if it is unknown
286+
// $info is what $response->getInfo() would return at this very time
287+
},
288+
];
289+
290+
Any exceptions thrown from the callback will be wrapped in an instance of
291+
``TransportExceptionInterface`` and will abort the request.
292+
231293
Advanced Options
232294
~~~~~~~~~~~~~~~~
233295

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

238300
Processing Responses
239301
--------------------
@@ -253,6 +315,9 @@ following methods::
253315
// gets the response body as a string
254316
$content = $response->getContent();
255317

318+
// cancels the request/response
319+
$response->cancel();
320+
256321
// returns info coming from the transport layer, such as "response_headers",
257322
// "redirect_count", "start_time", "redirect_url", etc.
258323
$httpInfo = $response->getInfo();
@@ -281,10 +346,6 @@ response sequentially instead of waiting for the entire response::
281346
$response = $httpClient->request('GET', $url, [
282347
// optional: if you don't want to buffer the response in memory
283348
'buffer' => false,
284-
// optional: to display details about the response progress
285-
'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
286-
// ...
287-
},
288349
]);
289350

290351
// Responses are lazy: this code is executed as soon as headers are received
@@ -299,6 +360,28 @@ response sequentially instead of waiting for the entire response::
299360
fwrite($fileHandler, $chunk->getContent());
300361
}
301362

363+
Canceling Responses
364+
~~~~~~~~~~~~~~~~~~~
365+
366+
To abort a request (e.g. because it didn't complete in due time, or you want to
367+
fetch only the first bytes of the response, etc.), you can either use the
368+
``cancel()`` method of ``ResponseInterface``::
369+
370+
$response->cancel()
371+
372+
Or throw an exception from a progress callback::
373+
374+
$response = $client->request('GET', 'https://...', [
375+
'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
376+
// ...
377+
378+
throw new \MyException();
379+
},
380+
]);
381+
382+
The exception will be wrapped in an instance of ``TransportExceptionInterface``
383+
and will abort the request.
384+
302385
Handling Exceptions
303386
~~~~~~~~~~~~~~~~~~~
304387

@@ -376,19 +459,6 @@ the "foreach" in the snippet with this one, the code becomes fully async::
376459
Use the ``user_data`` option combined with ``$response->getInfo('user_data')``
377460
to track the identity of the responses in your foreach loops.
378461

379-
Canceling Responses
380-
~~~~~~~~~~~~~~~~~~~
381-
382-
Responses can be canceled at any moment before they are completed using the
383-
``cancel()`` method::
384-
385-
foreach ($client->stream($responses) as $response => $chunk) {
386-
// ...
387-
388-
// if some condition happens, cancel the response
389-
$response->cancel();
390-
}
391-
392462
Dealing with Network Timeouts
393463
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
394464

@@ -538,7 +608,7 @@ PSR-18 Compatibility
538608
--------------------
539609

540610
This component uses and implements abstractions defined by the
541-
``symfony/contracts`` package. It also implements the `PSR-18`_ (HTTP Client)
611+
``symfony/http-client-contracts``. It also implements the `PSR-18`_ (HTTP Client)
542612
specifications via the :class:`Symfony\\Component\\HttpClient\\Psr18Client`
543613
class, which is an adapter to turn a Symfony ``HttpClientInterface`` into a
544614
PSR-18 ``ClientInterface``.

reference/configuration/framework.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ This service can be configured using ``framework.http_client.default_options``:
678678
http_client:
679679
max_host_connections: 10
680680
default_options:
681-
headers: [{ 'X-Powered-By': 'ACME App' }]
681+
headers: { 'X-Powered-By': 'ACME App' }
682682
max_redirects: 7
683683
684684
.. _reference-http-client-scoped-clients:

0 commit comments

Comments
 (0)