@@ -128,8 +128,8 @@ The HTTP client supports different authentication mechanisms. They can be
128
128
defined globally when creating the client (to apply it to all requests) and to
129
129
each request (which overrides any global authentication)::
130
130
131
- // Use the same authentication for all requests
132
- $client = HttpClient::create( [
131
+ // Use the same authentication for all requests to https://example.com/
132
+ $client = HttpClient::createForBaseUri('https://example.com/', [
133
133
// HTTP Basic authentication (there are multiple ways of configuring it)
134
134
'auth_basic' => ['the-username'],
135
135
'auth_basic' => ['the-username', 'the-password'],
@@ -154,10 +154,12 @@ each request (which overrides any global authentication)::
154
154
.. note ::
155
155
156
156
The NTLM authentication mechanism requires using the cURL transport.
157
+ By using ``HttpClient::createForBaseUri() ``, we ensure that the auth credentials
158
+ won't be sent to any other hosts than https://example.com/.
157
159
158
160
.. versionadded :: 4.4
159
161
160
- The ``auth_ntlm `` option was introduced in Symfony 4.4.
162
+ The ``auth_ntlm `` option and the `` HttpClient::createForBaseUri() `` method were introduced in Symfony 4.4.
161
163
162
164
Query String Parameters
163
165
~~~~~~~~~~~~~~~~~~~~~~~
@@ -378,10 +380,7 @@ Call the ``stream()`` method of the HTTP client to get *chunks* of the
378
380
response sequentially instead of waiting for the entire response::
379
381
380
382
$url = 'https://releases.ubuntu.com/18.04.1/ubuntu-18.04.1-desktop-amd64.iso';
381
- $response = $client->request('GET', $url, [
382
- // optional: if you don't want to buffer the response in memory
383
- 'buffer' => false,
384
- ]);
383
+ $response = $client->request('GET', $url);
385
384
386
385
// Responses are lazy: this code is executed as soon as headers are received
387
386
if (200 !== $response->getStatusCode()) {
@@ -395,6 +394,14 @@ response sequentially instead of waiting for the entire response::
395
394
fwrite($fileHandler, $chunk->getContent());
396
395
}
397
396
397
+ .. note ::
398
+
399
+ By default, ``text/* ``, JSON and XML response bodies are buffered in a local
400
+ ``php://temp `` stream. You can control this behavior by using the ``buffer ``
401
+ option: set it to ``true ``/``false `` to enable/disable buffering, or to a
402
+ closure that should return the same based on the response headers it receives
403
+ as argument.
404
+
398
405
Canceling Responses
399
406
~~~~~~~~~~~~~~~~~~~
400
407
@@ -534,6 +541,8 @@ response and get remaining contents that might come back in a new timeout, etc.
534
541
is idle *. Big responses can last as long as needed to complete, provided they
535
542
remain active during the transfer and never pause for longer than specified.
536
543
544
+ Use the ``max_duration `` option to limit the time a full request/response can last.
545
+
537
546
Dealing with Network Errors
538
547
~~~~~~~~~~~~~~~~~~~~~~~~~~~
539
548
@@ -659,15 +668,15 @@ or if it matches the ``https://api.github.com/`` base URI.
659
668
Interoperability
660
669
----------------
661
670
662
- The component is interoperable with three different abstractions for HTTP
663
- clients: `Symfony Contracts `_, `PSR-18 `_ and `HTTPlug `_ v1 and v2. If your
664
- application uses libraries that need any of them, the component is compatible
671
+ The component is interoperable with four different abstractions for HTTP
672
+ clients: `Symfony Contracts `_, `PSR-18 `_, `HTTPlug `_ v1/v2 and native PHP streams.
673
+ If your application uses libraries that need any of them, the component is compatible
665
674
with all of them. They also benefit from :ref: `autowiring aliases <service-autowiring-alias >`
666
675
when the :ref: `framework bundle <framework-bundle-configuration >` is used.
667
676
668
677
If you are writing or maintaining a library that makes HTTP requests, you can
669
678
decouple it from any specific HTTP client implementations by coding against
670
- either Symfony Contracts (recommended) or PSR-18 (which superseded HTTPlug) .
679
+ either Symfony Contracts (recommended), PSR-18 or HTTPlug v2 .
671
680
672
681
Symfony Contracts
673
682
~~~~~~~~~~~~~~~~~
@@ -694,7 +703,7 @@ interface you need to code against when a client is needed::
694
703
All request options mentioned above (e.g. timeout management) are also defined
695
704
in the wordings of the interface, so that any compliant implementations (like
696
705
this component) is guaranteed to provide them. That's a major difference with
697
- the PSR-18 abstraction , which provides none related to the transport itself.
706
+ the other abstractions , which provide none related to the transport itself.
698
707
699
708
Another major feature covered by the Symfony Contracts is async/multiplexing,
700
709
as described in the previous sections.
@@ -719,6 +728,10 @@ To use it, you need the ``psr/http-client`` package and a `PSR-17`_ implementati
719
728
# with autowiring aliases provided by Symfony Flex
720
729
$ composer require nyholm/psr7
721
730
731
+ # alternatively, install the php-http/discovery package to auto-discover
732
+ # any already installed implementations from common vendors:
733
+ # composer require php-http/discovery
734
+
722
735
Now you can make HTTP requests with the PSR-18 client as follows::
723
736
724
737
use Symfony\Component\HttpClient\Psr18Client;
@@ -742,11 +755,11 @@ HTTPlug
742
755
743
756
Support for HTTPlug was introduced in Symfony 4.4.
744
757
745
- The `HTTPlug `_ specification was published before PSR-18 and is superseded by
746
- it. As such, you should not use it in newly written code. Yet, many libraries
747
- still require v1 or v2 of it. The component is interoperable with them thanks to
748
- the :class: `Symfony\\ Component\\ HttpClient\\ HttplugClient ` adapter class. Similarly
749
- to ``Psr18Client `` implementing relevant parts of PSR-17, ``HttplugClient `` also
758
+ The `HTTPlug `_ v1 specification was published before PSR-18 and is superseded by
759
+ it. As such, you should not use it in newly written code. The component is still
760
+ interoperable with libraries that require it thanks to the
761
+ :class: `Symfony\\ Component\\ HttpClient\\ HttplugClient ` class. Similarly to
762
+ ``Psr18Client `` implementing relevant parts of PSR-17, ``HttplugClient `` also
750
763
implements the factory methods defined in the related ``php-http/message-factory ``
751
764
package.
752
765
@@ -758,6 +771,10 @@ package.
758
771
# with autowiring aliases provided by Symfony Flex
759
772
$ composer require nyholm/psr7
760
773
774
+ # alternatively, install the php-http/discovery package to auto-discover
775
+ # any already installed implementations from common vendors:
776
+ # composer require php-http/discovery
777
+
761
778
Let's say you want to instantiate a class with the following constructor,
762
779
that requires HTTPlug dependencies::
763
780
@@ -782,6 +799,76 @@ Because ``HttplugClient`` implements the three interfaces, you can use it this w
782
799
$httpClient = new HttplugClient();
783
800
$apiClient = new SomeSdk($httpClient, $httpClient, $httpClient);
784
801
802
+ If you'd like to work with promises, ``HttplugClient `` also implements the
803
+ ``HttpAsyncClient `` interface. To use it, you need to install the
804
+ ``guzzlehttp/promises `` package:
805
+
806
+ .. code-block :: terminal
807
+
808
+ $ composer require guzzlehttp/promises
809
+
810
+ Then you're ready to go::
811
+
812
+ use Psr\Http\Message\ResponseInterface;
813
+ use Symfony\Component\HttpClient\HttplugClient;
814
+
815
+ $httpClient = new HttplugClient();
816
+ $request = $httpClient->createRequest('GET', 'https://my.api.com/');
817
+ $promise = $httpClient->sendRequest($request)
818
+ ->then(
819
+ function (ResponseInterface $response) {
820
+ echo 'Got status '.$response->getStatusCode();
821
+
822
+ return $response;
823
+ },
824
+ function (\Throwable $exception) {
825
+ echo 'Error: '.$exception->getMessage();
826
+
827
+ throw $exception;
828
+ }
829
+ );
830
+
831
+ // after you're done with sending several requests,
832
+ // you must wait for them to complete concurrently
833
+
834
+ // wait for a specific promise to resolve while monitoring them all
835
+ $response = $promise->wait();
836
+
837
+ // wait maximum 1 second for pending promises to resolve
838
+ $httpClient->wait(1.0);
839
+
840
+ // wait for all remaining promises to resolve
841
+ $httpClient->wait();
842
+
843
+ Native PHP streams
844
+ ~~~~~~~~~~~~~~~~~~
845
+
846
+ .. versionadded :: 4.4
847
+
848
+ Support for native PHP streams was introduced in Symfony 4.4.
849
+
850
+ Responses implementing :class: `Symfony\\ Contracts\\ HttpClient\\ ResponseInterface `
851
+ can be cast to native PHP streams with
852
+ :method: `Symfony\\ Component\\ HttpClient\\ Response\\ StreamWrapper::createResource` `.
853
+ This allows using them where native PHP streams are needed::
854
+
855
+ use Symfony\Component\HttpClient\HttpClient;
856
+ use Symfony\Component\HttpClient\Response\StreamWrapper;
857
+
858
+ $client = HttpClient::create();
859
+ $response = $client->request('GET', 'https://symfony.com/versions.json');
860
+
861
+ $streamResource = StreamWrapper::createResource($response, $client);
862
+
863
+ // alternatively and contrary to the previous one, this returns
864
+ // a resource that is seekable and potentially stream_select()-able
865
+ $streamResource = $response->toStream();
866
+
867
+ echo stream_get_contents($streamResource); // outputs the content of the response
868
+
869
+ // later on if you need to, you can access the response from the stream
870
+ $response = stream_get_meta_data($streamResource)['wrapper_data']->getResponse();
871
+
785
872
Symfony Framework Integration
786
873
-----------------------------
787
874
0 commit comments