@@ -124,8 +124,8 @@ The HTTP client supports different authentication mechanisms. They can be
124
124
defined globally when creating the client (to apply it to all requests) and to
125
125
each request (which overrides any global authentication)::
126
126
127
- // Use the same authentication for all requests
128
- $client = HttpClient::create( [
127
+ // Use the same authentication for all requests to https://example.com/
128
+ $client = HttpClient::createForBaseUri('https://example.com/', [
129
129
// HTTP Basic authentication (there are multiple ways of configuring it)
130
130
'auth_basic' => ['the-username'],
131
131
'auth_basic' => ['the-username', 'the-password'],
@@ -150,6 +150,8 @@ each request (which overrides any global authentication)::
150
150
.. note ::
151
151
152
152
The NTLM authentication mechanism requires using the cURL transport.
153
+ By using ``HttpClient::createForBaseUri() ``, we ensure that the auth credentials
154
+ won't be sent to any other hosts than https://example.com/.
153
155
154
156
Query String Parameters
155
157
~~~~~~~~~~~~~~~~~~~~~~~
@@ -366,10 +368,7 @@ Call the ``stream()`` method of the HTTP client to get *chunks* of the
366
368
response sequentially instead of waiting for the entire response::
367
369
368
370
$url = 'https://releases.ubuntu.com/18.04.1/ubuntu-18.04.1-desktop-amd64.iso';
369
- $response = $client->request('GET', $url, [
370
- // optional: if you don't want to buffer the response in memory
371
- 'buffer' => false,
372
- ]);
371
+ $response = $client->request('GET', $url);
373
372
374
373
// Responses are lazy: this code is executed as soon as headers are received
375
374
if (200 !== $response->getStatusCode()) {
@@ -383,6 +382,14 @@ response sequentially instead of waiting for the entire response::
383
382
fwrite($fileHandler, $chunk->getContent());
384
383
}
385
384
385
+ .. note ::
386
+
387
+ By default, ``text/* ``, JSON and XML response bodies are buffered in a local
388
+ ``php://temp `` stream. You can control this behavior by using the ``buffer ``
389
+ option: set it to ``true ``/``false `` to enable/disable buffering, or to a
390
+ closure that should return the same based on the response headers it receives
391
+ as argument.
392
+
386
393
Canceling Responses
387
394
~~~~~~~~~~~~~~~~~~~
388
395
@@ -525,6 +532,8 @@ response and get remaining contents that might come back in a new timeout, etc.
525
532
is idle *. Big responses can last as long as needed to complete, provided they
526
533
remain active during the transfer and never pause for longer than specified.
527
534
535
+ Use the ``max_duration `` option to limit the time a full request/response can last.
536
+
528
537
Dealing with Network Errors
529
538
~~~~~~~~~~~~~~~~~~~~~~~~~~~
530
539
@@ -650,15 +659,15 @@ or if it matches the ``https://api.github.com/`` base URI.
650
659
Interoperability
651
660
----------------
652
661
653
- The component is interoperable with three different abstractions for HTTP
654
- clients: `Symfony Contracts `_, `PSR-18 `_ and `HTTPlug `_ v1 and v2. If your
655
- application uses libraries that need any of them, the component is compatible
662
+ The component is interoperable with four different abstractions for HTTP
663
+ clients: `Symfony Contracts `_, `PSR-18 `_, `HTTPlug `_ v1/v2 and native PHP streams.
664
+ If your application uses libraries that need any of them, the component is compatible
656
665
with all of them. They also benefit from :ref: `autowiring aliases <service-autowiring-alias >`
657
666
when the :ref: `framework bundle <framework-bundle-configuration >` is used.
658
667
659
668
If you are writing or maintaining a library that makes HTTP requests, you can
660
669
decouple it from any specific HTTP client implementations by coding against
661
- either Symfony Contracts (recommended) or PSR-18 (which superseded HTTPlug) .
670
+ either Symfony Contracts (recommended), PSR-18 or HTTPlug v2 .
662
671
663
672
Symfony Contracts
664
673
~~~~~~~~~~~~~~~~~
@@ -676,7 +685,7 @@ interface you need to code against when a client is needed::
676
685
677
686
public function __construct(HttpClientInterface $client)
678
687
{
679
- $this->client = $client
688
+ $this->client = $client;
680
689
}
681
690
682
691
// [...]
@@ -685,7 +694,7 @@ interface you need to code against when a client is needed::
685
694
All request options mentioned above (e.g. timeout management) are also defined
686
695
in the wordings of the interface, so that any compliant implementations (like
687
696
this component) is guaranteed to provide them. That's a major difference with
688
- the PSR-18 abstraction , which provides none related to the transport itself.
697
+ the other abstractions , which provide none related to the transport itself.
689
698
690
699
Another major feature covered by the Symfony Contracts is async/multiplexing,
691
700
as described in the previous sections.
@@ -710,6 +719,10 @@ To use it, you need the ``psr/http-client`` package and a `PSR-17`_ implementati
710
719
# with autowiring aliases provided by Symfony Flex
711
720
$ composer require nyholm/psr7
712
721
722
+ # alternatively, install the php-http/discovery package to auto-discover
723
+ # any already installed implementations from common vendors:
724
+ # composer require php-http/discovery
725
+
713
726
Now you can make HTTP requests with the PSR-18 client as follows::
714
727
715
728
use Symfony\Component\HttpClient\Psr18Client;
@@ -725,27 +738,26 @@ Now you can make HTTP requests with the PSR-18 client as follows::
725
738
HTTPlug
726
739
~~~~~~~
727
740
728
- The `HTTPlug `_ specification was published before PSR-18 and is superseded by
729
- it. As such, you should not use it in newly written code. Yet, many libraries
730
- still require v1 or v2 of it. The component is interoperable with them thanks to
731
- the ``HttplugClient `` adapter class. Similarly to ``Psr18Client `` implementing
732
- relevant parts of PSR-17, ``HttplugClient `` also implements the factory methods
733
- defined in the related ``php-http/message-factory `` package.
734
-
735
- Internally, the implementation relies on the ``Psr18Client ``, so that the
736
- ``psr/http-client `` package is needed to use this class:
741
+ The `HTTPlug `_ v1 specification was published before PSR-18 and is superseded by
742
+ it. As such, you should not use it in newly written code. The component is still
743
+ interoperable with libraries that require it thanks to the
744
+ :class: `Symfony\\ Component\\ HttpClient\\ HttplugClient ` class. Similarly to
745
+ ``Psr18Client `` implementing relevant parts of PSR-17, ``HttplugClient `` also
746
+ implements the factory methods defined in the related ``php-http/message-factory ``
747
+ package.
737
748
738
749
.. code-block :: terminal
739
750
740
751
# Let's suppose php-http/httplug is already required by the lib you want to use
741
752
742
- # installs the PSR-18 ClientInterface
743
- $ composer require psr/http-client
744
-
745
753
# installs an efficient implementation of response and stream factories
746
754
# with autowiring aliases provided by Symfony Flex
747
755
$ composer require nyholm/psr7
748
756
757
+ # alternatively, install the php-http/discovery package to auto-discover
758
+ # any already installed implementations from common vendors:
759
+ # composer require php-http/discovery
760
+
749
761
Let's say you want to instantiate a class with the following constructor,
750
762
that requires HTTPlug dependencies::
751
763
@@ -770,6 +782,72 @@ Because ``HttplugClient`` implements the three interfaces, you can use it this w
770
782
$httpClient = new HttplugClient();
771
783
$apiClient = new SomeSdk($httpClient, $httpClient, $httpClient);
772
784
785
+ If you'd like to work with promises, ``HttplugClient `` also implements the
786
+ ``HttpAsyncClient `` interface. To use it, you need to install the
787
+ ``guzzlehttp/promises `` package:
788
+
789
+ .. code-block :: terminal
790
+
791
+ $ composer require guzzlehttp/promises
792
+
793
+ Then you're ready to go::
794
+
795
+ use Psr\Http\Message\ResponseInterface;
796
+ use Symfony\Component\HttpClient\HttplugClient;
797
+
798
+ $httpClient = new HttplugClient();
799
+ $request = $httpClient->createRequest('GET', 'https://my.api.com/');
800
+ $promise = $httpClient->sendRequest($request)
801
+ ->then(
802
+ function (ResponseInterface $response) {
803
+ echo 'Got status '.$response->getStatusCode();
804
+
805
+ return $response;
806
+ },
807
+ function (\Throwable $exception) {
808
+ echo 'Error: '.$exception->getMessage();
809
+
810
+ throw $exception;
811
+ }
812
+ );
813
+
814
+ // after you're done with sending several requests,
815
+ // you must wait for them to complete concurrently
816
+
817
+ // wait for a specific promise to resolve while monitoring them all
818
+ $response = $promise->wait();
819
+
820
+ // wait maximum 1 second for pending promises to resolve
821
+ $httpClient->wait(1.0);
822
+
823
+ // wait for all remaining promises to resolve
824
+ $httpClient->wait();
825
+
826
+ Native PHP Streams
827
+ ~~~~~~~~~~~~~~~~~~
828
+
829
+ Responses implementing :class: `Symfony\\ Contracts\\ HttpClient\\ ResponseInterface `
830
+ can be cast to native PHP streams with
831
+ :method: `Symfony\\ Component\\ HttpClient\\ Response\\ StreamWrapper::createResource` `.
832
+ This allows using them where native PHP streams are needed::
833
+
834
+ use Symfony\Component\HttpClient\HttpClient;
835
+ use Symfony\Component\HttpClient\Response\StreamWrapper;
836
+
837
+ $client = HttpClient::create();
838
+ $response = $client->request('GET', 'https://symfony.com/versions.json');
839
+
840
+ $streamResource = StreamWrapper::createResource($response, $client);
841
+
842
+ // alternatively and contrary to the previous one, this returns
843
+ // a resource that is seekable and potentially stream_select()-able
844
+ $streamResource = $response->toStream();
845
+
846
+ echo stream_get_contents($streamResource); // outputs the content of the response
847
+
848
+ // later on if you need to, you can access the response from the stream
849
+ $response = stream_get_meta_data($streamResource)['wrapper_data']->getResponse();
850
+
773
851
Symfony Framework Integration
774
852
-----------------------------
775
853
0 commit comments