杰瑞科技汇

Python WSGIRequest 是什么?如何使用?

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

Python WSGIRequest 是什么?如何使用?-图1
(图片来源网络,侵删)

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:

  1. The environ Dictionary: 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).
  2. The start_response Callable: 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.

    Python WSGIRequest 是什么?如何使用?-图2
    (图片来源网络,侵删)

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:

  1. Print the entire environ dictionary to the console (for demonstration).
  2. Display the key request information in the HTML response.
  3. 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

  1. Save the code: Save the code above as my_wsgi_app.py.

  2. 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.
  3. 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 printed environ dictionary.

  4. Test with POST data: Use a tool like curl to send a POST request with data.

    • Open a new terminal window.
    • Run the following curl command:
      curl -X POST -d "username=testuser&message=hello wsgi" http://localhost:8000/
    • You will see the HTML response in the curl terminal, showing the echoed POST data.
    • In your server terminal, you will see a new, much larger environ dictionary printed, now containing CONTENT_LENGTH, wsgi.input data, and other headers related to the POST request.

Key Takeaways

  • environ is 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.util is Your Helper: Use functions like setup_testing_defaults for development and request_uri for reliable URI construction.
  • wsgi.input is for the Body: To read data from a POST or PUT request, you read from the file-like object at environ['wsgi.input'].
  • WSGI is the Foundation: Understanding the raw environ dictionary 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.
分享:
扫描分享到社交APP
上一篇
下一篇