Я пытаюсь создать веб-сервер 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 на своем терминале и перехожу по URL-адресу http://локальный:8080/ в своем браузере. Однако, когда я отправляю форму, я получаю сообщение об ошибке в браузере. Вывод терминала показывает ошибку, в которой говорится, что «невозможно объединить «str» с «nonetype». Из-за этой ошибки значения формы не передаются на эту страницу. Либо так, либо HTTP-сервер передает их в качестве параметров запроса. В любом случае, смогу ли я использовать класс cgi.FieldStorage внутри моего HTTP-сервера для доступа к значениям полей формы?
Примерно через неделю поиска решения этой проблемы я обнаружил, что модуль http.server Python на самом деле несовместим с модулем cgi. Модуль cgi используется внутри сценариев Python, которым передаются значения формы из некоторого документа HTML на веб-сервере (например, форма на странице index.html веб-сервера с атрибутом «действие», установленным для рассматриваемого сценария Python) . Однако для того, чтобы модуль cgi имел доступ к значениям формы, переданным этому сценарию (через вызов cgi.FieldStorage()), сценарий должен выполняться внутри веб-сервера. Проблема с моим примером кода выше заключается в том, что сценарий server.py, который я создал, сам является веб-сервером. В частности, он создает экземпляр HTTPServer, используя собственный класс обработчика запросов, который я создаю (TestServerHandler). Мой пользовательский класс является подклассом класса CGIHTTPRequestHandler, содержащегося в модуле http.server. Этот класс содержит метод 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 имеет конструктор, определенный для эта страница. Важными параметрами являются fp
, headers
и environ
. OP прав в том, что cgi.FieldStorage() обычно вызывается без параметров в сценарии CGI, и в этом случае параметры заполняются за вас. Однако мы можем создать объект FieldStorage с переменными, которые нам предоставляет CGIHTTPRequestHandler
:
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ = {
'REQUEST_METHOD': 'POST',
'CONTENT_TYPE': self.headers['Content-Type'],
}