0
# Request and Response Handling
1
2
Complete WSGI request and response wrappers providing high-level access to HTTP data including headers, cookies, form data, file uploads, content negotiation, and conditional requests. These classes form the foundation of Werkzeug's web development capabilities.
3
4
## Capabilities
5
6
### Request Object
7
8
The Request class wraps a WSGI environ dictionary, providing convenient access to all request data with automatic parsing and type conversion.
9
10
```python { .api }
11
class Request:
12
def __init__(self, environ, populate_request=True, shallow=False):
13
"""
14
Create a new request wrapper.
15
16
Parameters:
17
- environ: WSGI environment dictionary
18
- populate_request: Whether to parse form data immediately
19
- shallow: Don't consume input stream for form parsing
20
"""
21
22
# URL and path information
23
method: str # HTTP method (GET, POST, etc.)
24
url: str # Complete URL
25
base_url: str # URL without query string
26
url_root: str # Protocol, host, and script root
27
path: str # Path portion of URL
28
script_root: str # SCRIPT_NAME from WSGI
29
query_string: str # Raw query string
30
31
# Request data access
32
args: MultiDict # Parsed query parameters
33
form: MultiDict # Parsed form data (POST/PUT)
34
files: MultiDict # Uploaded files as FileStorage objects
35
values: MultiDict # Combined args and form data
36
data: bytes # Raw request body
37
json: Any # Parsed JSON data (if Content-Type is JSON)
38
39
# Headers and metadata
40
headers: Headers # Request headers
41
cookies: dict # Request cookies
42
authorization: Optional[Authorization] # Authorization header
43
# User-Agent header accessible via headers.get('User-Agent')
44
45
# Accept headers for content negotiation
46
accept_mimetypes: MIMEAccept # Accept header
47
accept_charsets: CharsetAccept # Accept-Charset header
48
accept_encodings: Accept # Accept-Encoding header
49
accept_languages: LanguageAccept # Accept-Language header
50
51
# Conditional request headers
52
cache_control: RequestCacheControl # Cache-Control header
53
if_match: Optional[ETags] # If-Match header
54
if_none_match: Optional[ETags] # If-None-Match header
55
if_modified_since: Optional[datetime] # If-Modified-Since header
56
if_unmodified_since: Optional[datetime] # If-Unmodified-Since header
57
range: Optional[Range] # Range header
58
59
# Content information
60
content_type: Optional[str] # Content-Type header
61
content_length: Optional[int] # Content-Length header
62
mimetype: Optional[str] # MIME type from Content-Type
63
mimetype_params: dict # Parameters from Content-Type
64
65
# Request type checks
66
is_json: bool # True if Content-Type is JSON
67
is_secure: bool # True if request is over HTTPS
68
is_xhr: bool # True if X-Requested-With is XMLHttpRequest
69
70
# Client and server information
71
remote_addr: Optional[str] # Client IP address
72
remote_user: Optional[str] # Authenticated username
73
scheme: str # URL scheme (http/https)
74
host: str # Host header value
75
port: Optional[int] # Port number
76
77
def get_json(self, force=False, silent=False, cache=True):
78
"""
79
Parse request body as JSON.
80
81
Parameters:
82
- force: Parse even if Content-Type is not JSON
83
- silent: Return None instead of raising on parse errors
84
- cache: Cache parsed result
85
86
Returns:
87
Parsed JSON data or None
88
"""
89
```
90
91
### Response Object
92
93
The Response class provides a high-level interface for creating HTTP responses with proper header management, cookie handling, and caching support.
94
95
```python { .api }
96
class Response:
97
def __init__(self, response=None, status=None, headers=None, mimetype=None, content_type=None, direct_passthrough=False):
98
"""
99
Create a new response object.
100
101
Parameters:
102
- response: Response body (string, bytes, or iterable)
103
- status: HTTP status code or status line
104
- headers: Response headers (dict, list, or Headers object)
105
- mimetype: MIME type for Content-Type header
106
- content_type: Complete Content-Type header value
107
- direct_passthrough: Don't modify response body
108
"""
109
110
# Response data and status
111
data: bytes # Response body as bytes
112
status: str # Complete status line (e.g., "200 OK")
113
status_code: int # Status code number
114
headers: Headers # Response headers
115
116
# Content type information
117
mimetype: Optional[str] # MIME type portion
118
content_type: Optional[str] # Complete Content-Type header
119
content_length: Optional[int] # Content-Length header
120
121
# Caching headers
122
cache_control: ResponseCacheControl # Cache-Control header
123
expires: Optional[datetime] # Expires header
124
last_modified: Optional[datetime] # Last-Modified header
125
etag: Optional[str] # ETag header
126
127
# Other headers
128
www_authenticate: Optional[WWWAuthenticate] # WWW-Authenticate header
129
location: Optional[str] # Location header for redirects
130
131
def set_cookie(self, key, value="", max_age=None, expires=None, path="/", domain=None, secure=False, httponly=False, samesite=None):
132
"""
133
Set a cookie.
134
135
Parameters:
136
- key: Cookie name
137
- value: Cookie value
138
- max_age: Maximum age in seconds
139
- expires: Expiration datetime or timestamp
140
- path: Cookie path
141
- domain: Cookie domain
142
- secure: Only send over HTTPS
143
- httponly: Don't allow JavaScript access
144
- samesite: SameSite attribute ('Strict', 'Lax', or 'None')
145
"""
146
147
def delete_cookie(self, key, path="/", domain=None, secure=False, httponly=False, samesite=None):
148
"""
149
Delete a cookie by setting it to expire immediately.
150
151
Parameters:
152
- key: Cookie name to delete
153
- path: Cookie path (must match original)
154
- domain: Cookie domain (must match original)
155
- secure: Secure flag (must match original)
156
- httponly: HttpOnly flag (must match original)
157
- samesite: SameSite attribute (must match original)
158
"""
159
160
def set_etag(self, etag, weak=False):
161
"""
162
Set the ETag header.
163
164
Parameters:
165
- etag: ETag value
166
- weak: Whether this is a weak ETag
167
"""
168
169
def make_conditional(self, request_or_environ, accept_ranges=False, complete_length=None):
170
"""
171
Make response conditional based on request headers.
172
173
Handles If-Match, If-None-Match, If-Modified-Since, If-Unmodified-Since
174
and Range headers automatically.
175
176
Parameters:
177
- request_or_environ: Request object or WSGI environ
178
- accept_ranges: Whether to accept Range requests
179
- complete_length: Total content length for partial content
180
181
Returns:
182
Response object (may be modified for 304/416 responses)
183
"""
184
185
def add_etag(self, overwrite=False, weak=False):
186
"""
187
Add an ETag header based on response content.
188
189
Parameters:
190
- overwrite: Replace existing ETag
191
- weak: Generate weak ETag
192
"""
193
194
def freeze(self, no_etag=False):
195
"""
196
Make response immutable and add ETag if missing.
197
198
Parameters:
199
- no_etag: Don't add ETag header
200
"""
201
```
202
203
### Response Stream
204
205
Helper for streaming responses with proper chunked encoding support.
206
207
```python { .api }
208
class ResponseStream:
209
def __init__(self, response):
210
"""
211
Create a response stream wrapper.
212
213
Parameters:
214
- response: Response object to wrap
215
"""
216
217
def write(self, data):
218
"""
219
Write data to response stream.
220
221
Parameters:
222
- data: Data to write (string or bytes)
223
"""
224
225
def writelines(self, lines):
226
"""
227
Write multiple lines to response stream.
228
229
Parameters:
230
- lines: Iterable of lines to write
231
"""
232
233
def close(self):
234
"""Close the response stream."""
235
```
236
237
## Usage Examples
238
239
### Basic Request Handling
240
241
```python
242
from werkzeug.wrappers import Request, Response
243
244
def application(environ, start_response):
245
request = Request(environ)
246
247
# Access request data
248
method = request.method
249
path = request.path
250
user_agent = request.headers.get('User-Agent')
251
252
# Handle different content types
253
if request.is_json:
254
data = request.get_json()
255
response = Response(f"Received JSON: {data}")
256
elif request.method == 'POST':
257
form_data = request.form
258
response = Response(f"Form data: {dict(form_data)}")
259
else:
260
response = Response("Hello World!")
261
262
return response(environ, start_response)
263
```
264
265
### File Upload Handling
266
267
```python
268
from werkzeug.wrappers import Request, Response
269
from werkzeug.utils import secure_filename
270
import os
271
272
def handle_upload(environ, start_response):
273
request = Request(environ)
274
275
if request.method == 'POST':
276
uploaded_file = request.files.get('file')
277
if uploaded_file and uploaded_file.filename:
278
filename = secure_filename(uploaded_file.filename)
279
upload_path = os.path.join('/uploads', filename)
280
uploaded_file.save(upload_path)
281
response = Response(f"File {filename} uploaded successfully")
282
else:
283
response = Response("No file uploaded", status=400)
284
else:
285
response = Response('''
286
<form method="POST" enctype="multipart/form-data">
287
<input type="file" name="file">
288
<input type="submit" value="Upload">
289
</form>
290
''', mimetype='text/html')
291
292
return response(environ, start_response)
293
```
294
295
### Content Negotiation
296
297
```python
298
from werkzeug.wrappers import Request, Response
299
import json
300
301
def api_endpoint(environ, start_response):
302
request = Request(environ)
303
304
data = {"message": "Hello", "status": "success"}
305
306
# Check what the client accepts
307
if request.accept_mimetypes.accept_json:
308
response = Response(
309
json.dumps(data),
310
mimetype='application/json'
311
)
312
elif request.accept_mimetypes.accept_html:
313
html = f"<h1>{data['message']}</h1><p>Status: {data['status']}</p>"
314
response = Response(html, mimetype='text/html')
315
else:
316
# Default to plain text
317
response = Response(f"{data['message']} - {data['status']}")
318
319
return response(environ, start_response)
320
```
321
322
### Conditional Responses and Caching
323
324
```python
325
from werkzeug.wrappers import Request, Response
326
from werkzeug.http import http_date
327
from datetime import datetime
328
329
def cached_content(environ, start_response):
330
request = Request(environ)
331
332
# Create response with content
333
content = "This is cached content that changes infrequently"
334
response = Response(content)
335
336
# Set caching headers
337
response.last_modified = datetime(2023, 1, 1)
338
response.cache_control.max_age = 3600 # Cache for 1 hour
339
response.add_etag() # Generate ETag from content
340
341
# Make response conditional (handles 304 Not Modified)
342
response.make_conditional(request)
343
344
return response(environ, start_response)
345
```
346
347
### Cookie Handling
348
349
```python
350
from werkzeug.wrappers import Request, Response
351
352
def session_example(environ, start_response):
353
request = Request(environ)
354
355
# Read existing session
356
session_id = request.cookies.get('session_id')
357
358
if session_id:
359
response = Response(f"Welcome back! Session: {session_id}")
360
else:
361
# Create new session
362
import uuid
363
new_session_id = str(uuid.uuid4())
364
response = Response(f"New session created: {new_session_id}")
365
366
# Set secure session cookie
367
response.set_cookie(
368
'session_id',
369
new_session_id,
370
max_age=3600, # 1 hour
371
secure=True, # HTTPS only
372
httponly=True, # No JavaScript access
373
samesite='Lax' # CSRF protection
374
)
375
376
return response(environ, start_response)
377
```