Skip to content

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:

RangeMeaningExamples
2xxSuccess200 OK, 201 Created
3xxRedirection301 Moved, 304 Not Modified
4xxClient error400 Bad Request, 404 Not Found
5xxServer error500 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 >= 400

5.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_code or resp.is_success;
  • resp.raise_for_status() raises an exception on failure (recommended);
  • Use .content for binary data and .json() for JSON;
  • Handle large files with stream=True plus iter_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 ​

  1. Request a 404 from httpbin and check the status code using all three approaches.
  2. Stream-download a file larger than 1 MB, recording elapsed time and memory usage.
  3. Set a 2-second timeout against a slow endpoint and catch the Timeout exception.