Как работают функции Python SimpleHTTPServer do_GET и do_POST?

1

Я создал следующий небольшой 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()

Мои предположения таковы:

  • Мой класс "ServerHandler" расширяет класс SimpleHTTPServer.SimpleHTTPRequestHandler двумя функциями: go_GET и do_POST
  • Функция main() создает объект обработчика сервера и серверный сокет, привязанный к моему IP-адресу и выбранному порту, и вызывает функцию для обслуживания/прослушивания на неопределенный срок.

Кроме того: я знаю, глядя на 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 функции?

Теги:
server
simplehttpserver

1 ответ

0
Лучший ответ

Когда вы вызываете 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

(заметьте, я дважды хешировал (##) мои комментарии, чтобы отделить их от оригинального автора)

  • 0
    @ Джо Лддон - Спасибо, это фантастический ответ. Теперь я понимаю. К сожалению, мой пользовательский рейтинг не достаточен, чтобы проголосовать за этот ответ. еще раз спасибо

Ещё вопросы

Сообщество Overcoder
Наверх
Меню