You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过本地Python HTTP服务器以CGI方式运行带参数的Python脚本

Hey there! Let's tackle your custom HTTP server issue. You want it to run any Python script and pass CGI parameters just like your old Apache setup, right? Let's break down what's wrong with your current code and fix it step by step.

Problem with Your Current Code

Your existing server has three main gaps preventing it from working as expected:

  • Hardcoded script path: You're running my_site.py directly, so there's no way to point to other Python files.
  • Missing CGI environment variables: The cgi.FieldStorage() in your target script relies on variables like QUERY_STRING and REQUEST_METHOD (which Apache automatically sets for CGI scripts). Your current code doesn't pass these, so the script can't read parameters.
  • Unsafe/limited execution: Using os.popen() is risky and doesn't handle POST request bodies properly.

Fixed Solution: Custom CGI Server

Here's a revised version of your server that addresses all these issues. It supports both GET and POST requests, lets you specify any Python script via the URL path, and properly passes CGI parameters to the target script:

from http.server import CGIHTTPRequestHandler, HTTPServer
import os
import subprocess
from urllib.parse import urlparse, parse_qs

class CustomCGIHandler(CGIHTTPRequestHandler):
    # Allow any path to act as a CGI script (adjust to restrict to specific directories if needed)
    cgi_directories = ['/']

    def _execute_script(self, script_path, env, input_data=None):
        """Helper function to execute the target Python script and return output"""
        try:
            result = subprocess.run(
                ['python3', script_path],
                input=input_data,
                capture_output=True,
                text=True,
                env=env
            )
            return result.stdout, result.stderr
        except Exception as e:
            return "", f"Execution error: {str(e)}"

    def do_GET(self):
        # Parse URL to get script path and query parameters
        parsed_url = urlparse(self.path)
        script_path = parsed_url.path.lstrip('/')
        
        # Check if the script exists
        if not os.path.isfile(script_path):
            self.send_error(404, f"Script '{script_path}' not found")
            return

        # Set required CGI environment variables
        env = os.environ.copy()
        env.update({
            'REQUEST_METHOD': 'GET',
            'QUERY_STRING': parsed_url.query,
            'PATH_INFO': parsed_url.path,
            'CONTENT_TYPE': self.headers.get('Content-Type', ''),
            'REMOTE_ADDR': self.client_address[0],
            'HTTP_HOST': self.headers.get('Host', '')
        })

        # Execute the script
        stdout, stderr = self._execute_script(script_path, env)

        # Send response
        self.send_response(200)
        self.send_header('Content-Type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(stdout.encode('utf-8'))
        
        # Include error output if present
        if stderr:
            self.wfile.write(f"<pre><b>Script Errors:</b>\n{stderr}</pre>".encode('utf-8'))

    def do_POST(self):
        # Parse URL and get script path
        parsed_url = urlparse(self.path)
        script_path = parsed_url.path.lstrip('/')
        
        if not os.path.isfile(script_path):
            self.send_error(404, f"Script '{script_path}' not found")
            return

        # Read POST request body
        content_length = int(self.headers.get('Content-Length', 0))
        post_data = self.rfile.read(content_length).decode('utf-8') if content_length > 0 else ""

        # Set POST-specific CGI environment variables
        env = os.environ.copy()
        env.update({
            'REQUEST_METHOD': 'POST',
            'QUERY_STRING': parsed_url.query,
            'PATH_INFO': parsed_url.path,
            'CONTENT_TYPE': self.headers.get('Content-Type', 'application/x-www-form-urlencoded'),
            'CONTENT_LENGTH': str(content_length),
            'REMOTE_ADDR': self.client_address[0],
            'HTTP_HOST': self.headers.get('Host', '')
        })

        # Execute script with POST data as input
        stdout, stderr = self._execute_script(script_path, env, input_data=post_data)

        # Send response
        self.send_response(200)
        self.send_header('Content-Type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(stdout.encode('utf-8'))
        
        if stderr:
            self.wfile.write(f"<pre><b>Script Errors:</b>\n{stderr}</pre>".encode('utf-8'))

if __name__ == '__main__':
    server = HTTPServer(('localhost', 8080), CustomCGIHandler)
    print('Starting server, use <Ctrl-C> to stop')
    server.serve_forever()

Testing the Setup

Let's create a test script (test.py) to verify everything works:

#!/usr/bin/python3
import cgi

# Read CGI parameters
form = cgi.FieldStorage()
filename = form.getvalue('filename', 'No filename provided')

# Print HTTP response header (required for CGI)
print("Content-Type: text/html; charset=utf-8\n")

# Output the result
print(f"<h1>CGI Parameter Test</h1>")
print(f"<p>Filename received: <b>{filename}</b></p>")

Test GET Request

Run the server, then visit:
http://127.0.0.1:8080/test.py?filename=yomomma

You should see the output: Filename received: yomomma

Test POST Request

Use curl (or Postman) to send a POST request:

curl -X POST -d "filename=test_post_value" http://127.0.0.1:8080/test.py

The response should show: Filename received: test_post_value

Key Takeaways

  • CGI Environment Variables: These are critical for cgi.FieldStorage() to work. We're setting the same variables Apache would, like REQUEST_METHOD, QUERY_STRING, and (for POST) CONTENT_LENGTH.
  • Flexible Script Execution: The server now uses the URL path to find the script (e.g., /test.py runs test.py in the server's working directory).
  • Safety & Error Handling: Using subprocess.run() is more secure than os.popen(), and we capture script errors to help with debugging.

内容的提问来源于stack exchange,提问作者LordOdin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:22:03