The allow_redirects
parameter in Python's requests
library controls whether HTTP redirects are automatically followed. This parameter is essential for handling redirect responses (3xx status codes) in web scraping and API interactions.
Default Behavior
By default, allow_redirects=True
for GET and HEAD requests, meaning the library automatically follows redirects to their final destination:
import requests
# Automatically follows redirects (default behavior)
response = requests.get('https://httpbin.org/redirect/3')
print(f"Final URL: {response.url}")
print(f"Status code: {response.status_code}") # 200
print(f"Redirect history: {len(response.history)} redirects")
Disabling Redirects
Set allow_redirects=False
to capture the initial redirect response without following it:
import requests
# Disable automatic redirects
response = requests.get('https://httpbin.org/redirect/1', allow_redirects=False)
print(f"Status code: {response.status_code}") # 302
print(f"Original URL: {response.url}")
print(f"Redirect location: {response.headers.get('Location')}")
print(f"Is redirect: {response.is_redirect}")
Redirect Types Handled
The allow_redirects
parameter handles these HTTP status codes:
- 301 - Moved Permanently
- 302 - Found (Temporary Redirect)
- 303 - See Other
- 307 - Temporary Redirect
- 308 - Permanent Redirect
Practical Examples
Manual Redirect Handling
import requests
def handle_redirects_manually(url, max_redirects=5):
"""Follow redirects manually with custom logic"""
redirect_count = 0
current_url = url
while redirect_count < max_redirects:
response = requests.get(current_url, allow_redirects=False)
if not response.is_redirect:
return response
# Custom logic before following redirect
print(f"Redirect {redirect_count + 1}: {response.status_code}")
current_url = response.headers['Location']
redirect_count += 1
raise Exception(f"Too many redirects (>{max_redirects})")
# Usage
final_response = handle_redirects_manually('https://httpbin.org/redirect/3')
Inspecting Redirect Cookies
import requests
# Capture cookies set during redirects
session = requests.Session()
response = session.get('https://httpbin.org/cookies/set/session/abc123',
allow_redirects=False)
print(f"Cookies after redirect response: {session.cookies}")
print(f"Location header: {response.headers.get('Location')}")
# Now follow the redirect
final_response = session.get(response.headers['Location'])
print(f"Final response cookies: {final_response.json()}")
Detecting Redirect Loops
import requests
def safe_request(url, max_redirects=10):
"""Make request with redirect loop protection"""
try:
response = requests.get(url, allow_redirects=True,
timeout=30, stream=False)
if len(response.history) > max_redirects:
print(f"Warning: {len(response.history)} redirects followed")
return response
except requests.TooManyRedirects:
print("Redirect loop detected!")
return None
HTTP Method Differences
Important: allow_redirects
behavior varies by HTTP method:
import requests
# GET and HEAD: allow_redirects=True by default
get_response = requests.get('https://httpbin.org/redirect/1')
head_response = requests.head('https://httpbin.org/redirect/1')
# POST, PUT, DELETE: allow_redirects=False by default
post_response = requests.post('https://httpbin.org/redirect/1')
put_response = requests.put('https://httpbin.org/redirect/1')
print(f"GET follows redirects: {len(get_response.history) > 0}")
print(f"POST follows redirects: {len(post_response.history) > 0}")
Common Use Cases
Web Scraping
# Check for redirects before scraping
response = requests.get(target_url, allow_redirects=False)
if response.is_redirect:
print(f"Page moved to: {response.headers['Location']}")
# Update your scraping target
API Integration
# Handle API endpoint changes
api_response = requests.get(api_endpoint, allow_redirects=False)
if api_response.status_code == 301:
new_endpoint = api_response.headers['Location']
print(f"API endpoint permanently moved to: {new_endpoint}")
Security Auditing
# Detect open redirects
test_url = f"https://example.com/redirect?url=https://malicious.com"
response = requests.get(test_url, allow_redirects=False)
if response.is_redirect:
redirect_target = response.headers.get('Location')
if 'malicious.com' in redirect_target:
print("Open redirect vulnerability detected!")
Best Practices
- Default behavior is usually correct - Most applications should use the default
allow_redirects=True
- Disable for manual control - Set to
False
when you need to inspect or customize redirect handling - Monitor redirect chains - Long redirect chains can impact performance
- Handle redirect loops - Use appropriate timeout and redirect limits
- Preserve authentication - Be aware that redirects might cross domain boundaries