@@ -182,7 +182,7 @@ processed automatically when making the requests::
182
182
'body' => ['parameter1' => 'value1', '...'],
183
183
184
184
// using a closure to generate the uploaded data
185
- 'body' => function () {
185
+ 'body' => function (int $size): string {
186
186
// ...
187
187
},
188
188
@@ -195,12 +195,39 @@ When uploading data with the ``POST`` method, if you don't define the
195
195
form data and adds the required
196
196
``'Content-Type: application/x-www-form-urlencoded' `` header for you.
197
197
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.
201
201
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(),
204
231
]);
205
232
206
233
Cookies
@@ -228,12 +255,47 @@ making a request. Use the ``max_redirects`` setting to configure this behavior
228
255
'max_redirects' => 0,
229
256
]);
230
257
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
+
231
293
Advanced Options
232
294
~~~~~~~~~~~~~~~~
233
295
234
296
The :class: `Symfony\\ Contracts\\ HttpClient\\ HttpClientInterface ` defines all the
235
297
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.
237
299
238
300
Processing Responses
239
301
--------------------
@@ -253,6 +315,9 @@ following methods::
253
315
// gets the response body as a string
254
316
$content = $response->getContent();
255
317
318
+ // cancels the request/response
319
+ $response->cancel();
320
+
256
321
// returns info coming from the transport layer, such as "response_headers",
257
322
// "redirect_count", "start_time", "redirect_url", etc.
258
323
$httpInfo = $response->getInfo();
@@ -281,10 +346,6 @@ response sequentially instead of waiting for the entire response::
281
346
$response = $httpClient->request('GET', $url, [
282
347
// optional: if you don't want to buffer the response in memory
283
348
'buffer' => false,
284
- // optional: to display details about the response progress
285
- 'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
286
- // ...
287
- },
288
349
]);
289
350
290
351
// 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::
299
360
fwrite($fileHandler, $chunk->getContent());
300
361
}
301
362
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
+
302
385
Handling Exceptions
303
386
~~~~~~~~~~~~~~~~~~~
304
387
@@ -376,19 +459,6 @@ the "foreach" in the snippet with this one, the code becomes fully async::
376
459
Use the ``user_data `` option combined with ``$response->getInfo('user_data') ``
377
460
to track the identity of the responses in your foreach loops.
378
461
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
-
392
462
Dealing with Network Timeouts
393
463
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
394
464
@@ -538,7 +608,7 @@ PSR-18 Compatibility
538
608
--------------------
539
609
540
610
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)
542
612
specifications via the :class: `Symfony\\ Component\\ HttpClient\\ Psr18Client `
543
613
class, which is an adapter to turn a Symfony ``HttpClientInterface `` into a
544
614
PSR-18 ``ClientInterface ``.
0 commit comments