杰瑞科技汇

Python HTTPHandler如何实现自定义请求处理?

Of course! Let's dive deep into Python's http.server module and its BaseHTTPRequestHandler and SimpleHTTPRequestHandler classes. This is a fantastic tool for understanding the fundamentals of how web servers work.

Python HTTPHandler如何实现自定义请求处理?-图1
(图片来源网络,侵删)

What is http.server?

The http.server module in Python's standard library contains a simple HTTP server framework. It's perfect for:

  • Learning: Understanding the HTTP request-response cycle.
  • Development: Quickly serving files from a directory for a local project.
  • Testing: Creating a mock server to test API clients against.
  • Simple Prototyping: Building a basic web service without the overhead of a full framework like Flask or Django.

The Core Concept: BaseHTTPRequestHandler

At the heart of this module is the BaseHTTPRequestHandler class. When you start a server using this module, for every incoming HTTP request, it creates an instance of this handler class. This instance's job is to:

  1. Parse the incoming request (method, path, headers, etc.).
  2. Call a specific method based on the request's method (e.g., do_GET, do_POST).
  3. Build and send an HTTP response back to the client.

You typically create a custom handler class that inherits from BaseHTTPRequestHandler and overrides its methods to define your server's behavior.


A Practical Example: A Simple "Hello, World!" Server

Let's create a basic server that responds to GET requests.

Python HTTPHandler如何实现自定义请求处理?-图2
(图片来源网络,侵删)

Step 1: Create the Server Script

Create a file named my_server.py and add the following code:

# my_server.py
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
# Define the port and host
PORT = 8000
HOST = 'localhost'  # Use '0.0.0.0' to make it accessible from other machines on the network
# Create a custom handler by inheriting from BaseHTTPRequestHandler
class MySimpleHandler(BaseHTTPRequestHandler):
    """
    This handler will respond to GET and POST requests.
    """
    # The 'do_GET' method is called when the server receives a GET request.
    def do_GET(self):
        # 1. Send a response code
        self.send_response(200)
        # 2. Send headers
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        # 3. Send the response body (the actual content)
        # We use json.dumps to create a JSON string from a Python dictionary
        response_data = {
            "message": "Hello, World!",
            "status": "success",
            "path": self.path
        }
        # We need to encode the string to bytes before sending it
        self.wfile.write(json.dumps(response_data).encode('utf-8'))
    # The 'do_POST' method is called when the server receives a POST request.
    def do_POST(self):
        # 1. Send a response code
        self.send_response(201) # 201 Created is a good status for a POST request
        # 2. Send headers
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        # 3. Read the body of the POST request
        # The content length header tells us how many bytes to read
        content_length = int(self.headers['Content-Length'])
        post_data = self.rfile.read(content_length)
        # Decode the bytes to a string and parse it as JSON
        try:
            received_json = json.loads(post_data.decode('utf-8'))
            response_message = f"Data received: {received_json}"
        except (json.JSONDecodeError, UnicodeDecodeError):
            response_message = "Error: Invalid JSON data."
            self.send_response(400) # Bad Request
            self.end_headers()
            self.wfile.write(response_message.encode('utf-8'))
            return
        # 4. Send a success response
        response_data = {
            "message": response_message,
            "status": "data received"
        }
        self.wfile.write(json.dumps(response_data).encode('utf-8'))
# This is the standard way to start the server
if __name__ == '__main__':
    # Create an instance of the server
    server = HTTPServer((HOST, PORT), MySimpleHandler)
    print(f"Server started at http://{HOST}:{PORT}")
    try:
        # Keep the server running forever
        server.serve_forever()
    except KeyboardInterrupt:
        # Shut down the server gracefully when Ctrl+C is pressed
        print("\nServer is shutting down...")
        server.server_close()

Step 2: Run the Server

Open your terminal or command prompt, navigate to the directory where you saved my_server.py, and run it:

python my_server.py

You should see the output: Server started at http://localhost:8000

Step 3: Test the Server

Open a new terminal window (don't close the one running the server!).

Python HTTPHandler如何实现自定义请求处理?-图3
(图片来源网络,侵删)

Test the GET request: Use a tool like curl or simply open your web browser and navigate to http://localhost:8000.

Using curl:

curl http://localhost:8000

Expected Output:

{
  "message": "Hello, World!",
  "path": "/",
  "status": "success"
}

Test the POST request: Use curl with the -X POST flag and -d to send data.

curl -X POST -H "Content-Type: application/json" -d '{"name": "Alice", "id": 123}' http://localhost:8000

Expected Output:

{
  "message": "Data received: {'name': 'Alice', 'id': 123}",
  "status": "data received"
}

To stop the server, go back to its terminal window and press Ctrl+C.


Key Attributes and Methods of the Handler Class

When a request comes in, an instance of your handler class is created. Here are the most useful attributes and methods you'll work with:

Useful Attributes

  • self.client_address: A tuple (host, port) of the client.
  • self.command: The request method (e.g., 'GET', 'POST').
  • self.path: The path requested by the client (e.g., '/api/users').
  • self.headers: An http.client.HTTPMessage object containing the request headers.
  • self.rfile: An input stream (file-like object) to read the request body from.
  • self.wfile: An output stream (file-like object) to write the response body to.

Useful Methods

  • self.send_response(code): Sends the HTTP response status code (e.g., 200, 404).
  • self.send_header(keyword, value): Sends a specific HTTP header (e.g., Content-type, Content-Length).
  • self.end_headers(): Sends a blank line, signaling the end of the headers section. This must be called before you start writing to self.wfile.
  • self.wfile.write(data): Writes the response body. The data must be in bytes.

The Easier Way: SimpleHTTPRequestHandler

For the common task of serving static files from a directory, Python provides a ready-made handler called SimpleHTTPRequestHandler. You don't need to write any custom logic for this.

Example: Serving Files

  1. Create a directory for your project, for example, my_website.

  2. Inside my_website, create an index.html file:

    <!DOCTYPE html>
    <html>
    <head>
        <title>My Awesome Website</title>
    </head>
    <body>
        <h1>Hello from a Python server!</h1>
        <p>This is an HTML file being served by SimpleHTTPRequestHandler.</p>
    </body>
    </html>
  3. Create a style.css file in the same directory:

    body {
        font-family: sans-serif;
        background-color: #f0f0f0;
    }
    h1 {
        color: #333;
    }
  4. Create a Python script named run_server.py inside the my_website directory:

    # run_server.py
    from http.server import SimpleHTTPRequestHandler, HTTPServer
    import os
    PORT = 8000
    HOST = 'localhost'
    # The server will serve files from the current directory
    # os.getcwd() gets the current working directory
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    server = HTTPServer((HOST, PORT), SimpleHTTPRequestHandler)
    print(f"Serving files from: {os.getcwd()}")
    print(f"Server started at http://{HOST}:{PORT}")
    print("Open your browser and navigate to the above URL.")
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\nServer is shutting down...")
        server.server_close()
  5. Run the script from inside the my_website directory:

    python run_server.py
  6. Open your browser to http://localhost:8000. You will see your index.html page. You can also access http://localhost:8000/style.css to see the CSS file.

Note: SimpleHTTPRequestHandler is very convenient but also very basic. It does not support directory listings by default in recent Python versions, and it has no security features. It is not recommended for production use.


Summary and Best Practices

Feature BaseHTTPRequestHandler SimpleHTTPRequestHandler
Purpose Building a custom web server with specific logic. Quickly serving static files from a directory.
Customization High. You override do_GET, do_POST, etc. Low. It's a pre-built handler.
Use Case APIs, dynamic content, learning HTTP. Local development, quick file sharing.
Security You are responsible for security. Not secure for production. No authentication, no protection against directory traversal, etc.

When to use http.server:

  • For learning and prototyping.
  • For local development of a front-end project.
  • As a mock server during testing.

When to use a real framework (like Flask, Django, FastAPI):

  • For production applications.
  • When you need features like routing, templating, ORMs, security, sessions, and scalability.
分享:
扫描分享到社交APP
上一篇
下一篇