diff --git a/docs/quickstart.md b/docs/quickstart.md index 38da2fec36..13a446a76e 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -305,6 +305,23 @@ The method returns the response instance, allowing you to use it inline. For exa >>> data = httpx.get('...').raise_for_status().json() ``` +### Controlling Redirect Behavior + +By default, `raise_for_status()` will raise an exception for redirect responses (3xx status codes). However, when you make a request with `follow_redirects=False`, the method automatically detects this and won't raise exceptions for redirect responses: + +```pycon +# This will raise an exception for redirects (default behavior) +response = httpx.get('https://httpbin.org/status/301') +response.raise_for_status() # Raises HTTPStatusError for 301 redirect + +# This will NOT raise an exception for redirects +response = httpx.get('https://httpbin.org/status/301', follow_redirects=False) +response.raise_for_status() # No exception raised - treats redirect as successful +``` + +When `follow_redirects=False` is set on the request, HTTPX sets `response.next_request` for redirect responses, and `raise_for_status()` automatically detects this and treats redirects as successful responses. + + ## Response Headers The response headers are available as a dictionary-like interface. diff --git a/httpx/_models.py b/httpx/_models.py index 2cc86321a4..33146d686c 100644 --- a/httpx/_models.py +++ b/httpx/_models.py @@ -805,6 +805,10 @@ def raise_for_status(self) -> Response: if self.is_success: return self + # If follow_redirects is False, we should not raise a redirect error + if self.next_request is not None: + return self + if self.has_redirect_location: message = ( "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n" diff --git a/tests/models/test_responses.py b/tests/models/test_responses.py index 06c28e1e30..91df8a81f0 100644 --- a/tests/models/test_responses.py +++ b/tests/models/test_responses.py @@ -145,6 +145,14 @@ def test_raise_for_status(): with pytest.raises(RuntimeError): response.raise_for_status() + # If follow_redirects is False, we should not raise a redirect error + request_with_follow_redirects_false = httpx.Request( + "GET", "https://example.org", extensions={"follow_redirects": False} + ) + response = httpx.Response(303, request=request_with_follow_redirects_false) + response.next_request = httpx.Request("GET", "https://other.org") + assert response.raise_for_status() is response + def test_response_repr(): response = httpx.Response(