Chapter 5 · Responses in Depth
Chapter goals: master status-code checking, JSON parsing, binary handling, and streaming responses.
5.1 Checking Status Codes
HTTP status codes indicate the outcome of a request:
| Range | Meaning | Examples |
|---|---|---|
| 2xx | Success | 200 OK, 201 Created |
| 3xx | Redirection | 301 Moved, 304 Not Modified |
| 4xx | Client error | 400 Bad Request, 404 Not Found |
| 5xx | Server error | 500 Internal Server Error |
python
import requests
resp = requests.get('https://httpbin.org/status/404')
# Option 1: check manually
if resp.status_code == 200:
print('Success')
elif resp.status_code == 404:
print('Not found')
else:
print(f'Other status: {resp.status_code}')
# Option 2: the is_success property (True for 2xx)
if resp.is_success:
print('Success')
else:
print(f'Failed: {resp.status_code}')
# Option 3: raise_for_status() (recommended; raises on failure)
resp.raise_for_status() # raises HTTPError if status >= 4005.2 Handling JSON Responses
python
import requests
import json
resp = requests.get('https://api.github.com/users/octocat')
# Parse JSON
data = resp.json()
print(data['name'])
# Check whether it's a JSON response
if resp.headers.get('Content-Type', '').startswith('application/json'):
data = resp.json()
else:
print('Non-JSON response:', resp.text[:100])
# Handling JSON parse errors
try:
data = resp.json()
except requests.exceptions.JSONDecodeError as e:
print(f'JSON parsing failed: {e}')
print('Raw response:', resp.text[:200])5.3 Binary Response Handling
For images, files, audio and similar payloads:
python
import requests
# Download an image
resp = requests.get('https://httpbin.org/image/png')
# Save it to disk
with open('download.png', 'wb') as f:
f.write(resp.content)
# Work with binary data in memory
image_data = resp.content
# Can be handed to PIL, cv2, etc.5.4 Streaming Responses
Use stream=True for large files so the whole body isn't loaded into memory:
python
import requests
# Streaming download of a large file
with requests.get('https://httpbin.org/stream/20', stream=True) as resp:
resp.raise_for_status()
# Read content incrementally
for line in resp.iter_lines():
if line:
print(line.decode('utf-8'))
# Downloading a large file to disk
url = 'https://httpbin.org/drip?numbytes=500000&delay=1'
with requests.get(url, stream=True) as resp:
resp.raise_for_status()
total = int(resp.headers.get('content-length', 0))
with open('large_file.bin', 'wb') as f:
for chunk in resp.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
# Optional: show progress
# print(f'\rDownloaded: {f.tell()}/{total}', end='')iter_content() and iter_lines() are the key methods for stream processing.
5.5 Response Timeouts
python
import requests
# Set a timeout (seconds)
try:
resp = requests.get('https://httpbin.org/delay/5', timeout=3)
except requests.exceptions.Timeout:
print('Request timed out')
# Separate connect and read timeouts
resp = requests.get(url, timeout=(5, 10)) # (connect_timeout, read_timeout)
# httpx equivalent
import httpx
client = httpx.Client(timeout=10.0)
resp = client.get(url)5.6 Chapter Summary
- Check outcomes via
resp.status_codeorresp.is_success; resp.raise_for_status()raises an exception on failure (recommended);- Use
.contentfor binary data and.json()for JSON; - Handle large files with
stream=Trueplusiter_content(); - Always set sensible timeouts.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. When does resp.raise_for_status() raise an exception?
2. What is the main advantage of stream=True?
3. What does timeout=(5, 10) mean?
4. Which property should you use to handle binary responses such as images?
🛠️ Hands-On Exercises
- Request a 404 from httpbin and check the status code using all three approaches.
- Stream-download a file larger than 1 MB, recording elapsed time and memory usage.
- Set a 2-second timeout against a slow endpoint and catch the Timeout exception.