Of course. The 302 Found HTTP status code is a fundamental concept in web browsing and API interaction, and the requests library in Python handles it in a specific way.

Here's a comprehensive guide covering what a 302 is, how requests deals with it by default, and how to control its behavior.
What is a 302 Redirect?
A 302 Found (also known as a "temporary redirect") is an HTTP response status code that tells the client (your Python script) that the resource it requested has been temporarily moved to a different URL.
- Purpose: The server is saying, "The thing you asked for isn't here right now, but you can find it at this other address. Please use that new address for this request only."
- Key Characteristic: It's temporary. The server expects the client to continue using the original URL for future requests.
How requests Handles 302 by Default
The requests library is designed to behave like a web browser. By default, it is configured to follow redirects automatically.
This means if you send a request to a URL that returns a 302 status code, requests will:

- Receive the
302response. - Automatically see the
Locationheader in the response, which contains the new URL. - Send a new GET request to that
LocationURL. - Return the response from this final, successful request to you.
The Response object you get back will contain the content, headers, and status code of the final destination, not the original 302 redirect.
Example: Default Behavior (Following Redirects)
Let's use httpbin.org, a fantastic service for testing HTTP requests. It has an endpoint that returns a 302 redirect.
import requests
# The URL that will give us a 302 redirect
url = "http://httpbin.org/redirect/1" # This will redirect to http://httpbin.org/get
try:
# By default, allow_redirects=True
response = requests.get(url)
print(f"Original URL: {url}")
print("-" * 30)
# The response object is for the FINAL destination
print(f"Final URL: {response.url}")
print(f"Final Status Code: {response.status_code}")
print(f"History (shows redirects): {response.history}")
# The history attribute is a list of Response objects from the intermediate redirects
if response.history:
print("\nRedirect chain:")
for r in response.history:
print(f" - Redirected from {r.url} with status {r.status_code}")
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
Output:
Original URL: http://httpbin.org/redirect/1
------------------------------
Final URL: http://httpbin.org/get
Final Status Code: 200
History (shows redirects): [<Response [302]>]
Redirect chain:
- Redirected from http://httpbin.org/redirect/1 with status 302
As you can see:

response.urlis the final URL (http://httpbin.org/get).response.status_codeis200(OK), not302.response.historycontains a list of the intermediate redirect responses.
How to Control Redirect Behavior
Sometimes, you don't want requests to follow redirects automatically. The most common reason is to inspect the redirect itself—to see the Location header or check the original 302 status code.
You can disable this behavior using the allow_redirects parameter.
Example: Disabling Redirects
Set allow_redirects=False in your request. requests will stop and return the 302 response immediately.
import requests
url = "http://httpbin.org/redirect/1"
try:
# Set allow_redirects=False to stop at the 302
response = requests.get(url, allow_redirects=False)
print(f"Original URL: {url}")
print("-" * 30)
# The response object is now for the ORIGINAL request
print(f"Final URL: {response.url}") # Still the original URL
print(f"Status Code: {response.status_code}") # This will be 302!
# The Location header contains the URL we would have been redirected to
print(f"Location Header: {response.headers.get('Location')}")
# History will be empty because we didn't follow any redirects
print(f"History: {response.history}")
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
Output:
Original URL: http://httpbin.org/redirect/1
------------------------------
Final URL: http://httpbin.org/redirect/1
Status Code: 302
Location Header: http://httpbin.org/get
History: []
This is incredibly useful for debugging or for applications that need to handle redirects manually.
Other Important Redirect Status Codes
While you asked about 302, it's good to know that requests handles them all with the same allow_redirects logic:
- 301 Moved Permanently: A permanent redirect.
requestsfollows it by default. Browsers often cache this, so they will directly request the new URL in the future without asking the server again. - 302 Found: A temporary redirect. The default behavior for
requests. - 303 See Other: The response to the request can be found under a different URI and should be retrieved using a GET method.
requestshandles this correctly by changing the method to GET for the subsequent request. - 307 Temporary Redirect: Very similar to 302, but it specifies that the request method (e.g., POST) and body must not be changed when redirecting.
requestsrespects this. - 308 Permanent Redirect: The permanent equivalent of 307. The method and body are not changed, and the redirect is permanent.
Summary Table
| Parameter | Value | Behavior | Use Case |
|---|---|---|---|
allow_redirects |
True (Default) |
requests automatically follows 302, 301, 303, 307, 308 redirects. The final response is returned. |
Most common use cases. You want the data from the final destination, like a user clicking a link. |
allow_redirects |
False |
requests stops at the first redirect (e.g., 302). The intermediate response (with the 302 status) is returned. |
Debugging, checking the Location header, or implementing custom redirect logic. |
Final Recommendation
- For 99% of cases: Use the default
allow_redirects=True. It's what you want when you're just trying to get data from a URL that might have moved. - When you need to debug or handle redirects manually: Use
allow_redirects=Falseto inspect the redirect headers and status codes before deciding how to proceed.
