0
# Response Handling
1
2
Response objects provide access to HTTP status codes, headers, and response metadata. Response objects behave like dictionaries for header access while providing additional status information and response details.
3
4
## Capabilities
5
6
### Response Class
7
8
HTTP response object that extends Python's dict class to provide dictionary-like access to headers while maintaining response status and metadata.
9
10
```python { .api }
11
class Response(dict):
12
"""
13
HTTP response containing status code, headers, and metadata.
14
Inherits from dict to provide header access via dictionary interface.
15
"""
16
17
def __init__(self, info):
18
"""
19
Initialize response from HTTP response info.
20
21
Args:
22
info: Either email.message or httplib.HTTPResponse object
23
"""
24
25
# Dictionary methods inherited from dict
26
# Additional attributes available:
27
# - status: HTTP status code (int)
28
# - reason: HTTP reason phrase (str)
29
# - version: HTTP version (int)
30
```
31
32
### Response Attributes
33
34
Response objects provide several key attributes:
35
36
```python { .api }
37
# Status information
38
response.status # HTTP status code (200, 404, 500, etc.)
39
response.reason # Reason phrase ("OK", "Not Found", etc.)
40
response.version # HTTP version (11 for HTTP/1.1)
41
42
# Dictionary interface for headers
43
response['content-type'] # Access headers by name
44
response['content-length'] # All header names are lowercase
45
response['cache-control'] # Headers stored as strings
46
response.get('etag', None) # Use dict methods for safe access
47
```
48
49
### Usage Examples
50
51
#### Accessing Response Status
52
53
```python
54
import httplib2
55
56
h = httplib2.Http()
57
(resp, content) = h.request("http://example.org/")
58
59
# Check status code
60
if resp.status == 200:
61
print("Request successful")
62
elif resp.status == 404:
63
print("Resource not found")
64
else:
65
print(f"Request failed with status {resp.status}: {resp.reason}")
66
```
67
68
#### Working with Headers
69
70
```python
71
import httplib2
72
73
h = httplib2.Http()
74
(resp, content) = h.request("http://example.org/")
75
76
# Access headers (case-insensitive, stored as lowercase)
77
content_type = resp['content-type']
78
content_length = resp.get('content-length', 'unknown')
79
server = resp.get('server', 'unknown')
80
81
# Check if header exists
82
if 'etag' in resp:
83
etag = resp['etag']
84
print(f"ETag: {etag}")
85
86
# Iterate over all headers
87
for header_name, header_value in resp.items():
88
print(f"{header_name}: {header_value}")
89
```
90
91
#### Cache-Related Headers
92
93
```python
94
import httplib2
95
96
h = httplib2.Http(".cache")
97
(resp, content) = h.request("http://example.org/")
98
99
# Check caching headers
100
cache_control = resp.get('cache-control', '')
101
expires = resp.get('expires', '')
102
etag = resp.get('etag', '')
103
last_modified = resp.get('last-modified', '')
104
105
print(f"Cache-Control: {cache_control}")
106
print(f"ETag: {etag}")
107
print(f"Last-Modified: {last_modified}")
108
109
# Check if response was served from cache
110
# (httplib2 adds custom headers to indicate cache status)
111
if 'fromcache' in resp:
112
print("Response served from cache")
113
```
114
115
#### Content Type and Encoding
116
117
```python
118
import httplib2
119
120
h = httplib2.Http()
121
(resp, content) = h.request("http://example.org/")
122
123
# Parse content type
124
content_type = resp.get('content-type', '')
125
if 'application/json' in content_type:
126
import json
127
data = json.loads(content.decode('utf-8'))
128
elif 'text/html' in content_type:
129
html = content.decode('utf-8')
130
elif 'image/' in content_type:
131
# Binary image data
132
with open('image.jpg', 'wb') as f:
133
f.write(content)
134
135
# Check encoding from content-type header
136
if 'charset=' in content_type:
137
charset = content_type.split('charset=')[1].split(';')[0]
138
text = content.decode(charset)
139
else:
140
# Default to UTF-8
141
text = content.decode('utf-8')
142
```
143
144
#### Authentication Headers
145
146
```python
147
import httplib2
148
149
h = httplib2.Http()
150
(resp, content) = h.request("http://example.org/protected")
151
152
# Check authentication requirements
153
if resp.status == 401:
154
www_auth = resp.get('www-authenticate', '')
155
if 'Basic' in www_auth:
156
print("Server requires Basic authentication")
157
elif 'Digest' in www_auth:
158
print("Server requires Digest authentication")
159
160
# Add credentials and retry
161
h.add_credentials('username', 'password')
162
(resp, content) = h.request("http://example.org/protected")
163
```
164
165
#### Redirect Information
166
167
```python
168
import httplib2
169
170
h = httplib2.Http()
171
(resp, content) = h.request("http://example.org/redirect")
172
173
# Check for redirects
174
if resp.status in (301, 302, 303, 307, 308):
175
location = resp.get('location', '')
176
print(f"Redirected to: {location}")
177
178
# httplib2 follows redirects automatically by default
179
# The final response will have the status of the final destination
180
```
181
182
### Response Processing Patterns
183
184
#### Error Handling
185
186
```python
187
import httplib2
188
189
h = httplib2.Http()
190
191
try:
192
(resp, content) = h.request("http://example.org/api/data")
193
194
if resp.status == 200:
195
# Success
196
data = content.decode('utf-8')
197
elif resp.status == 404:
198
print("Resource not found")
199
elif resp.status >= 400:
200
print(f"Client error: {resp.status} {resp.reason}")
201
elif resp.status >= 500:
202
print(f"Server error: {resp.status} {resp.reason}")
203
204
except httplib2.HttpLib2Error as e:
205
print(f"HTTP error: {e}")
206
```
207
208
#### Content Negotiation
209
210
```python
211
import httplib2
212
213
h = httplib2.Http()
214
headers = {'Accept': 'application/json, text/xml, */*'}
215
216
(resp, content) = h.request("http://api.example.com/data", headers=headers)
217
218
content_type = resp.get('content-type', '')
219
if 'application/json' in content_type:
220
import json
221
data = json.loads(content.decode('utf-8'))
222
elif 'text/xml' in content_type or 'application/xml' in content_type:
223
import xml.etree.ElementTree as ET
224
root = ET.fromstring(content.decode('utf-8'))
225
else:
226
# Handle other content types
227
text = content.decode('utf-8')
228
```
229
230
### Header Name Normalization
231
232
All header names in Response objects are normalized to lowercase for consistent access:
233
234
- `Content-Type` becomes `content-type`
235
- `Content-Length` becomes `content-length`
236
- `Cache-Control` becomes `cache-control`
237
- `WWW-Authenticate` becomes `www-authenticate`
238
239
This normalization ensures reliable header access regardless of how the server sends the headers.