Skip to content

[HttpClient] better explain how to deal with exceptions #13136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 15, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion components/http_client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,34 @@ When the HTTP status code of the response is in the 300-599 range (i.e. 3xx,
// instead the original response content (even if it's an error message)
$content = $response->getContent(false);

While responses are lazy, their destructor will always wait for headers to come
back. This means that the following request *will* complete; and if e.g. a 404
is returned, an exception will be thrown::

// because the returned value is not assigned to a variable, the destructor
// of the returned response will be called immediately and will throw if the
// status code is in the 300-599 range
$client->request('POST', 'https://...');

This in turn means that unassigned responses will fallback to synchronous requests.
If you want to make these requests concurrent, you can store their corresponding
responses in an array::

$responses[] = $client->request('POST', 'https://.../path1');
$responses[] = $client->request('POST', 'https://.../path2');
// ...

// This line will trigger the destructor of all responses stored in the array;
// they will complete concurrently and an exception will be thrown in case a
// status code in the 300-599 range is returned
unset($responses);

This behavior provided at destruction-time is part of the fail-safe design of the
component. No errors will be unnoticed: if you don't write the code to handle
errors, exceptions will notify you when needed. On the other hand, if you write
the error-handling code, you will opt-out from these fallback mecanisms as the
destructor won't have anything remaining to do.

Concurrent Requests
-------------------

Expand Down Expand Up @@ -583,7 +611,16 @@ catching ``TransportExceptionInterface`` in the foreach loop::

foreach ($client->stream($responses) as $response => $chunk) {
try {
if ($chunk->isLast()) {
if ($chunk->isTimeout()) {
// ... decide what to do when a timeout occurs
// if you want to stop a response that timed out, don't miss
// calling $response->cancel() or the destructor of the response
// will try to complete it one more time
} elseif ($chunk->isFirst()) {
// if you want to check the status code, you must do it when the
// first chunk arrived, using $response->getStatusCode();
// not doing so might trigger an HttpExceptionInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the response headers might not be arrived yet? I am not sure to understand in which case it can happen.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It happens because that's how the first chunk behaves : if status code is unchecked after it, an exception is thrown. I'm going to improve this

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a little bit confusing that the exception is thrown from the iterator(generator), so you can not catch it inside a for-each cycle and continue to process other requests.

} elseif ($chunk->isLast()) {
// ... do something with $response
}
} catch (TransportExceptionInterface $e) {
Expand Down