Of course! Let's dive deep into wsgiref.request, a crucial part of Python's Web Server Gateway Interface (WSGI) standard.

While there isn't a single class named WSGIRequest in the standard library, the concept of a "WSGI Request" is embodied by a specific dictionary and the environment that surrounds it. The wsgiref package provides tools for creating and handling these requests.
What is a WSGI Request?
In WSGI, a "request" isn't a single, elegant object like in frameworks like Django or Flask. Instead, it's represented by two main components:
-
The
environDictionary: This is a dictionary containing all the information about the request. It's the heart of the request object. It includes:- Request Method:
REQUEST_METHOD(e.g.,'GET','POST') - Request Path:
PATH_INFO(e.g.,'/hello/world') - Query String:
QUERY_STRING(e.g.,'name=John&age=30') - Server Information:
SERVER_NAME,SERVER_PORT - Headers: Headers are prefixed with
HTTP_and are in uppercase (e.g.,HTTP_HOST,HTTP_USER_AGENT,HTTP_CONTENT_TYPE). - Input Stream:
wsgi.input– A file-like object for reading the request body (e.g., for POST data).
- Request Method:
-
The
start_responseCallable: This is a function provided by the WSGI server. Your application calls it to send the HTTP status code and headers back to the client before sending the response body.
(图片来源网络,侵删)
The wsgiref package, specifically wsgiref.util, provides utility functions to make working with the environ dictionary easier.
Key Components in wsgiref
wsgiref.util.setup_testing_defaults(environ)
This is a very useful function for development and testing. It populates the environ dictionary with a set of default values, making it a "complete" request even if the server doesn't provide all the standard keys.
wsgiref.util.request_uri(environ)
This function constructs the full request URI from the environ dictionary, including the scheme, host, path, and query string. It's more reliable than manually concatenating PATH_INFO and QUERY_STRING.
wsgiref.util.application_uri(environ)
This function constructs the base URI of the application itself (scheme, host, and script root), without the specific path or query string.
Practical Example: A Simple WSGI Application
Let's build a minimal WSGI application to see how the environ dictionary works in practice. This example will use the built-in wsgiref.simple_server to run our application.
This application will:
- Print the entire
environdictionary to the console (for demonstration). - Display the key request information in the HTML response.
- Echo back any POST data sent to it.
Code: my_wsgi_app.py
# my_wsgi_app.py
import sys
from wsgiref.simple_server import make_server
from wsgiref.util import setup_testing_defaults, request_uri
# A simple WSGI application
def simple_wsgi_app(environ, start_response):
"""
This is our WSGI application.
:param environ: A dictionary containing all request information.
:param start_response: A callable to begin the HTTP response.
"""
# 1. --- Setup and Logging ---
# For testing, we can add default values to environ
setup_testing_defaults(environ)
# Print the entire environ dictionary to the server's console
# This is great for debugging!
print("--- WSGI ENVIRON DICT ---")
for key, value in environ.items():
print(f"{key}: {value}")
print("-------------------------")
# 2. --- Process Request Information ---
request_method = environ.get('REQUEST_METHOD', 'GET')
path_info = environ.get('PATH_INFO', '/')
query_string = environ.get('QUERY_STRING', '')
content_length = int(environ.get('CONTENT_LENGTH', 0))
# Read the request body (if any)
request_body = environ['wsgi.input'].read(content_length).decode('utf-8')
# 3. --- Prepare the HTTP Response ---
status = '200 OK'
headers = [
('Content-Type', 'text/html; charset=utf-8'),
('Content-Length', str(len(response_body))),
]
# Build the HTML response body
response_body = f"""
<html>
<head><title>Simple WSGI App</title></head>
<body>
<h1>Hello from a WSGI Application!</h1>
<p><strong>Request Method:</strong> {request_method}</p>
<p><strong>Path Info:</strong> {path_info}</p>
<p><strong>Query String:</strong> {query_string}</p>
<p><strong>Full Request URI:</strong> {request_uri(environ)}</p>
<hr>
<h2>Request Body (POST data):</h2>
<pre>{request_body if request_body else '(No request body)'}</pre>
<hr>
<p>Check the server console for the full 'environ' dictionary!</p>
</body>
</html>
"""
# Encode the response body to bytes
response_body = response_body.encode('utf-8')
# 4. --- Start the Response and Send Body ---
start_response(status, headers)
# A WSGI application must return an iterable of bytes
return [response_body]
# --- Main execution block to run the server ---
if __name__ == '__main__':
host = 'localhost'
port = 8000
print(f"Starting WSGI server on http://{host}:{port}")
# Create a server and pass it our application
httpd = make_server(host, port, simple_wsgi_app)
print("Server is running. Press Ctrl+C to stop.")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\nServer stopped.")
httpd.server_close()
How to Run and Test
-
Save the code: Save the code above as
my_wsgi_app.py. -
Run the server: Open your terminal or command prompt, navigate to the directory where you saved the file, and run:
python my_wsgi_app.py
You should see the output:
Starting WSGI server on http://localhost:8000 Server is running. Press Ctrl+C to stop. -
Test with a browser: Open your web browser and go to
http://localhost:8000. You will see the HTML page. In your terminal where the server is running, you will see the printedenvirondictionary. -
Test with POST data: Use a tool like
curlto send a POST request with data.- Open a new terminal window.
- Run the following
curlcommand:curl -X POST -d "username=testuser&message=hello wsgi" http://localhost:8000/
- You will see the HTML response in the
curlterminal, showing the echoed POST data. - In your server terminal, you will see a new, much larger
environdictionary printed, now containingCONTENT_LENGTH,wsgi.inputdata, and other headers related to the POST request.
Key Takeaways
environis the Request Object: In WSGI, the request is a dictionary. This is a low-level but powerful and standardized way to pass request data.wsgiref.utilis Your Helper: Use functions likesetup_testing_defaultsfor development andrequest_urifor reliable URI construction.wsgi.inputis for the Body: To read data from a POST or PUT request, you read from the file-like object atenviron['wsgi.input'].- WSGI is the Foundation: Understanding the raw
environdictionary is key to understanding how high-level web frameworks like Flask, Django, and Pyramid work under the hood. They simply wrap this low-level interface with a more user-friendly, object-oriented API.
