使用 CGI 模块访问 Python http.server 中的表单数据值

Accessing Form Data Values in Python http.server Using CGI Module

我正在尝试创建一个 Python 网络服务器,它接受用户输入并向第三方 API 发出请求。用户输入是通过我创建的一个简单表单获得的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Test Document</title>
</head>
<body>
    <form action="server.py" method="post">
        <label for="firstname">First Name</label>
        <input type="text" name="firstname" id="firstname"><br>
        <label for="lastname">Last Name</label>
        <input type="text" name="lastname" id="lastname"><br>
        <label for="url">URL</label>
        <input type="text" name="url" id="application-url"><br>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

我将此文件命名为 index.html。我的 server.py 文件如下所示:

import cgi
from http.server import HTTPServer, CGIHTTPRequestHandler

class TestServerHandler(CGIHTTPRequestHandler):
    def do_POST(self):
        if self.path == '/':
            self.path = './index.html'

        try:
            form = cgi.FieldStorage()
            firstname = form.getvalue('firstname')
            lastname = form.getvalue('lastname')
            url = form.getvalue('url')
            print(firstname + ' ' + lastname + ' ' + url)
            output=firstname + lastname + url
        except: 
            self.send_error(404, 'Bad request submitted.')

        self.end_headers()
        self.wfile.write(bytes(output, 'utf-8'))


test_server = HTTPServer(('localhost', 8080), TestServerHandler)
test_server.serve_forever()

然后我在我的终端上 运行 server.py 文件,然后在我的浏览器中转到 http://localhost:8080/ url。但是,当我提交表单时,浏览器出现错误。终端输出显示一条错误消息“无法将 'str' 与 'nonetype' 连接起来。基于此错误,表单值未传递到此页面。那个或 HTTP 服务器将它们作为查询参数传递。在任何情况下,我都可以在我的 HTTP 服务器中使用 cgi.FieldStorage class 来访问表单字段值吗?

在寻找解决方案大约一周后,我发现 http.server Python 模块与 cgi 模块并不真正兼容。 cgi 模块在 Python 脚本中使用,这些脚本从 Web 服务器上的某些 HTML 文档传递表单值(即 Web 服务器 index.html 页面上的表单,带有 "action" 属性设置为有问题的 Python 脚本)。但是,为了使 cgi 模块能够访问传递给该脚本的表单值(通过 cgi.FieldStorage() 调用),该脚本必须位于 Web 服务器内 运行。我上面的代码示例的问题是我创建的 server.py 脚本本身就是一个网络服务器。具体来说,它使用我创建的自定义请求处理程序 class (TestServerHandler) 创建了一个 HTTPServer 实例。我的自定义 class 子 class 包含 http.server 模块中的 CGIHTTPRequestHandler class。此 class 包含 Do_POST 方法。实施此方法时,传递给 Python 脚本的任何表单数据都包含在 self.rfile 实例变量中。为了访问此变量并获取表单数据,我编写了与此类似的代码。

content_length = int(self.headers['Content-Length'])
data_input = bytes.decode(self.rfile.read(content_length))

将 form_data 存储在 data_input 变量中后,您可以使用 URL 解析器从表单访问所需的值。

FieldStorage class 具有在 this page 上定义的构造函数。它的重要参数是 fpheadersenviron。 OP是正确的,因为 cgi.FieldStorage() 通常在CGI脚本中调用时不带参数,在这种情况下会为您填写参数。但是,我们可以使用 CGIHTTPRequestHandler 为我们提供的变量创建一个 FieldStorage 对象:

form = cgi.FieldStorage(
        fp=self.rfile,
        headers=self.headers,
        environ={
            'REQUEST_METHOD': 'POST',
            'CONTENT_TYPE': self.headers['Content-Type'],
        }