Я создал следующий небольшой HTTP-сервер для обучения:
import SimpleHTTPServer
import SocketServer
class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
print(self.headers)
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
def do_POST(self):
print(self.headers)
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type'],
def main():
port = 50738
Handler = ServerHandler(1000)
httpd = SocketServer.TCPServer(("192.168.X.Y", port), Handler)
print "serving at port", port
httpd.serve_forever()
if __name__ == "__main__":
main()
Мои предположения таковы:
Кроме того: я знаю, глядя на DOC Python https://docs.python.org/2/library/simplehttpserver.html, что SimpleHTTPServer.SimpleHTTPRequestHandler имеет метод do_GET, который, как я полагаю, переопределяется do_GET в моем классе ServerHandler?
Вопрос: Что происходит под капотом, относящимся к do_GET и do_POST? Имеет ли место тот факт, что, как только этот сервер будет прослушивать "активность" HTTP, направленную на определенный IP: PORT, он автоматически узнает, является ли входящий сигнал GET или POST, и как только один из них встречается, сервер вызывает мой do_GET или do_POST функции?
Когда вы вызываете SocketServer.TCPServer
, вы назначаете класс Handler
как класс для приема входящих запросов.
Все, что вам SimpleHTTPServer
модуле SimpleHTTPServer
- это предоставление базовой функции HTTP, но вы можете написать все это самостоятельно.
Итак, как вы говорите, когда вы определяете Handler
, вы наследуете все методы из класса SimpleHTTPRequestHandler
, но затем переопределяете два из предопределенных методов: do_GET
и do_POST
. Вы также можете переопределить любые другие методы в классе.
Однако эти методы do_*
никогда не будут вызваны, если бы не метод handle
определенный в SimpleHTTPRequestHandler
поскольку он является этой функцией, socketserver
модулем socketserver
.
Поэтому, если вы просто наследуете socketserver.BaseRequestHandler
, вы потеряете всю функциональность, поскольку этот метод класса handle()
ничего не делает:
class socketserver.BaseRequestHandler
...
handle()
Эта функция должна выполнять всю работу, необходимую для обслуживания запроса. Реализация по умолчанию ничего не делает. Для него доступны несколько атрибутов экземпляра; запрос доступен как self.request; адрес клиента как self.client_address; и экземпляр сервера как self.server, если ему нужен доступ к информации на сервере.
...
Таким образом, импортируя SimpleHTTPRequestHandler
из модуля SimpleHTTPServer
, вы сразу получаете базовые функции для HTTP-сервера.
Вся эта функциональность документирована здесь, с важным битом в методе handle
:
class http.server.BaseHTTPRequestHandler(request, client_address, server)
...
handle()
Вызывает handle_one_request() один раз (или, если постоянные подключения включены, несколько раз) для обработки входящих HTTP-запросов. Вам не следует переопределять его; вместо этого реализуйте соответствующие методы do _ *().
handle_one_request()
Этот метод будет анализировать и отправлять запрос соответствующему методу do _ *(). Вам не следует переопределять его.
...
Итак, наконец, после того, как socketserver.TCPServer
вызовет метод handle()
для любого класса, который вы его передаете, мы видим, как SimpleHTTPRequestHandler
реализует это как передачу запроса на соответствующий do_GET
, do_POST
или любой другой метод в зависимости от заголовков запрос.
Если вы хотите посмотреть, как вы можете реализовать это самостоятельно, посмотрите исходный код либо в /usr/lib/pythonX.Y/http/server.py
либо на GitHub.
Мы можем видеть, что их тот SimpleHTTPServer
наследует BaseHTTPServer
где определены методы handle()
и handle_one_request()
:
Таким образом, как описывают документы, handle
просто передает запросы handle_one_request
, пока соединение не закрывается:
def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = True
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
и handle_one_request
- это то, где do_*
методы do_*
:
def handle_one_request(self):
"""Handle a single HTTP request.
You normally don't need to override this method; see the class
__doc__ string for information on how to handle specific HTTP
commands such as GET and POST.
"""
try:
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(HTTPStatus.REQUEST_URI_TOO_LONG)
return
if not self.raw_requestline:
self.close_connection = True
return
if not self.parse_request():
# An error code has been sent, just exit
return
mname = 'do_' + self.command ## the name of the method is created
if not hasattr(self, mname): ## checking that we have that method defined
self.send_error(
HTTPStatus.NOT_IMPLEMENTED,
"Unsupported method (%r)" % self.command)
return
method = getattr(self, mname) ## getting that method
method() ## finally calling it
self.wfile.flush() #actually send the response if not already done.
except socket.timeout as e:
#a read or a write timed out. Discard this connection
self.log_error("Request timed out: %r", e)
self.close_connection = True
return
(заметьте, я дважды хешировал (##
) мои комментарии, чтобы отделить их от оригинального автора)