@@ -186,7 +186,7 @@ processed automatically when making the requests::
186
186
'body' => ['parameter1' => 'value1', '...'],
187
187
188
188
// using a closure to generate the uploaded data
189
- 'body' => function () {
189
+ 'body' => function (int $size): string {
190
190
// ...
191
191
},
192
192
@@ -199,12 +199,39 @@ When uploading data with the ``POST`` method, if you don't define the
199
199
form data and adds the required
200
200
``'Content-Type: application/x-www-form-urlencoded' `` header for you.
201
201
202
- When uploading JSON payloads, use the ``json `` option instead of `` body ``. The
203
- given content will be JSON-encoded automatically and the request will add the
204
- `` Content-Type: application/json `` automatically too::
202
+ When the ``body `` option is set as a closure, it will be called several times until
203
+ it returns the empty string, which signals the end of the body. Each time, the
204
+ closure should return a string smaller than the amount requested as argument.
205
205
206
- $response = $httpClient->request('POST', 'https://...', [
207
- 'json' => ['param1' => 'value1', '...'],
206
+ A generator or any ``Traversable `` can also be used instead of a closure.
207
+
208
+ .. tip ::
209
+
210
+ When uploading JSON payloads, use the ``json `` option instead of ``body ``. The
211
+ given content will be JSON-encoded automatically and the request will add the
212
+ ``Content-Type: application/json `` automatically too::
213
+
214
+ $response = $httpClient->request('POST', 'https://...', [
215
+ 'json' => ['param1' => 'value1', '...'],
216
+ ]);
217
+
218
+ $decodedPayload = $response->toArray();
219
+
220
+ To submit a form with file uploads, it is your responsibility to encode the body
221
+ according to the ``multipart/form-data `` content-type. The
222
+ :doc: `Symfony Mime </components/mime >` component makes it a few lines of code::
223
+
224
+ use Symfony\Component\Mime\Part\DataPart;
225
+ use Symfony\Component\Mime\Part\Multipart\FormDataPart;
226
+
227
+ $formFields = [
228
+ 'regular_field' => 'some value',
229
+ 'file_field' => DataPart::fromPath('/path/to/uploaded/file'),
230
+ ];
231
+ $formData = new FormDataPart($formFields);
232
+ $client->request('POST', 'https://...', [
233
+ 'headers' => $formData->getPreparedHeaders()->toArray(),
234
+ 'body' => $formData->bodyToIterable(),
208
235
]);
209
236
210
237
Cookies
@@ -232,12 +259,47 @@ making a request. Use the ``max_redirects`` setting to configure this behavior
232
259
'max_redirects' => 0,
233
260
]);
234
261
262
+ HTTP Proxies
263
+ ~~~~~~~~~~~~
264
+
265
+ By default, this component honors the standard environment variables that your
266
+ Operating System defines to direct the HTTP traffic through your local proxy.
267
+ This means there is usually nothing to configure to have the client work with
268
+ proxies, provided these env vars are properly configured.
269
+
270
+ You can still set or override these settings using the ``proxy `` and ``no_proxy ``
271
+ options:
272
+
273
+ * ``proxy `` should be set to the ``http://... `` URL of the proxy to get through
274
+
275
+ * ``no_proxy `` disables the proxy for a comma-separated list of hosts that do not
276
+ require it to get reached.
277
+
278
+ Progress Callback
279
+ ~~~~~~~~~~~~~~~~~
280
+
281
+ By providing a callable to the ``on_progress `` option, one can track
282
+ uploads/downloads as they complete. This callback is guaranteed to be called on
283
+ DNS resolution, on arrival of headers and on completion; additionally it is
284
+ called when new data is uploaded or downloaded and at least once per second::
285
+
286
+ $response = $httpClient->request('GET', 'https://...', [
287
+ 'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
288
+ // $dlNow is the number of bytes downloaded so far
289
+ // $dlSize is the total size to be downloaded or -1 if it is unknown
290
+ // $info is what $response->getInfo() would return at this very time
291
+ },
292
+ ];
293
+
294
+ Any exceptions thrown from the callback will be wrapped in an instance of
295
+ ``TransportExceptionInterface `` and will abort the request.
296
+
235
297
Advanced Options
236
298
~~~~~~~~~~~~~~~~
237
299
238
300
The :class: `Symfony\\ Contracts\\ HttpClient\\ HttpClientInterface ` defines all the
239
301
options you might need to take full control of the way the request is performed,
240
- including progress monitoring, DNS pre-resolution, timeout, SSL parameters, etc.
302
+ including DNS pre-resolution, SSL parameters, public key pinning , etc.
241
303
242
304
Processing Responses
243
305
--------------------
@@ -257,6 +319,9 @@ following methods::
257
319
// gets the response body as a string
258
320
$content = $response->getContent();
259
321
322
+ // cancels the request/response
323
+ $response->cancel();
324
+
260
325
// returns info coming from the transport layer, such as "response_headers",
261
326
// "redirect_count", "start_time", "redirect_url", etc.
262
327
$httpInfo = $response->getInfo();
@@ -285,10 +350,6 @@ response sequentially instead of waiting for the entire response::
285
350
$response = $httpClient->request('GET', $url, [
286
351
// optional: if you don't want to buffer the response in memory
287
352
'buffer' => false,
288
- // optional: to display details about the response progress
289
- 'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
290
- // ...
291
- },
292
353
]);
293
354
294
355
// Responses are lazy: this code is executed as soon as headers are received
@@ -303,6 +364,28 @@ response sequentially instead of waiting for the entire response::
303
364
fwrite($fileHandler, $chunk->getContent());
304
365
}
305
366
367
+ Canceling Responses
368
+ ~~~~~~~~~~~~~~~~~~~
369
+
370
+ To abort a request (e.g. because it didn't complete in due time, or you want to
371
+ fetch only the first bytes of the response, etc.), you can either use the
372
+ ``cancel() `` method of ``ResponseInterface ``::
373
+
374
+ $response->cancel()
375
+
376
+ Or throw an exception from a progress callback::
377
+
378
+ $response = $client->request('GET', 'https://...', [
379
+ 'on_progress' => function (int $dlNow, int $dlSize, array $info): void {
380
+ // ...
381
+
382
+ throw new \MyException();
383
+ },
384
+ ]);
385
+
386
+ The exception will be wrapped in an instance of ``TransportExceptionInterface ``
387
+ and will abort the request.
388
+
306
389
Handling Exceptions
307
390
~~~~~~~~~~~~~~~~~~~
308
391
@@ -529,7 +612,7 @@ PSR-18 Compatibility
529
612
--------------------
530
613
531
614
This component uses and implements abstractions defined by the
532
- ``symfony/contracts `` package . It also implements the `PSR-18 `_ (HTTP Client)
615
+ ``symfony/http-client- contracts ``. It also implements the `PSR-18 `_ (HTTP Client)
533
616
specifications via the :class: `Symfony\\ Component\\ HttpClient\\ Psr18Client `
534
617
class, which is an adapter to turn a Symfony ``HttpClientInterface `` into a
535
618
PSR-18 ``ClientInterface ``.
0 commit comments