Сообщить об ошибке.

Модуль http.server в Python

Реализация HTTP веб-серверов

Модуль http.server определяет классы для реализации HTTP-серверов (веб-серверов).

Предупреждение модуль http.server не рекомендуется для использования в продакшне, так как он выполняет только базовые проверки безопасности.

Класс http.server.HTTPServer, является подклассом socketserver.TCPServer(). Он создает и прослушивает HTTP-сокет, отправляя запросы обработчику.

Код для создания и запуска сервера выглядит так:

def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler):
    server_address = ('', 8000)
    httpd = server_class(server_address, handler_class)
    httpd.serve_forever()

Классы HTTP веб-серверов.

http.server.HTTPServer(server_address, RequestHandlerClass):

Класс HTTPServer основан на классе TCPServer, сохраняя адрес сервера в виде переменных экземпляра с именами server_name и server_port.

Сервер доступен обработчику, обычно через переменную экземпляра сервера обработчика RequestHandlerClass.

http.server.ThreadingHTTPServer(server_address, RequestHandlerClass):

Класс ThreadingHTTPServer идентичен HTTPServer, но использует потоки для обработки запросов с помощью миксина ThreadingMixIn.

Такое поведение полезно для обработки запросов веб-браузеров, предварительно открывающих сокеты, на которых HTTPServer будет ждать бесконечно.

Классы HTTPServer и ThreadingHTTPServer должны получить в качестве аргумента RequestHandlerClass при создании экземпляра, из которых этот модуль предоставляет три различных варианта.

Обработчики HTTP-запросов:

  1. http.server.BaseHTTPRequestHandler() - класс используется для обработки HTTP-запросов, поступающих на сервер;
  2. http.server.SimpleHTTPRequestHandler() - обслуживает файлы из текущего каталога, напрямую сопоставляя структуру каталогов с HTTP-запросами;
  3. http.server.CGIHTTPRequestHandler() - обслуживает файлы или вывод сценариев CGI из текущего каталога.

Примеры создания простых HTTP web-серверов

Пример HTTP web-сервера, обрабатывающего статические файлы.

python3 -m http.server 8000 --bind 127.0.0.1

Если запустить HTTP сервер таким способом, то можно создать, например, фиктивный API путем загрузки на этот сервер статических файлов json или/и xml. Структура ресурсов файлов, организованных в подпапки, будет обеспечивать RESTful-подобные URL-адреса. Например, /users/all.json может содержать фиктивные записи пользователей. Этот подход еще быстрее, чем создание, например, приложения Flask. База данных не требуется, работает везде. Можно применять там, где например есть некоторые трудности с командой терминала scp для загрузки данных. Решение - можно запустить простой сервер на удаленной машине и загрузить необходимое содержимое через HTTP.

Пример HTTP web-сервера, с поддержкой SSL.

Для запуска защищенного HTTPs сервера создайте следующий модуль:

from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl


httpd = HTTPServer(('localhost', 4443), BaseHTTPRequestHandler)

httpd.socket = ssl.wrap_socket (httpd.socket, 
        keyfile="path/to/key.pem", 
        certfile='path/to/cert.pem', server_side=True)

httpd.serve_forever()

Для создания файлов ключей и сертификатов с помощью OpenSSL используйте следующую команду

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365

Пример HTTP web-сервера, обрабатывающего запросы GET и POST.

Это очень простой пример HTTP-сервера, который отвечает Hello, world! на запросы. Обратите внимание, что self.send_response(200) и self.end_headers() являются обязательными, в противном случае ответ не будет считаться действительным. Проверить работу сервера можно при помощи утилиты терминала curl.

from http.server import HTTPServer, BaseHTTPRequestHandler

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):

    # определяем метод `do_GET` 
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b'Hello, world!')


httpd = HTTPServer(('localhost', 8000), SimpleHTTPRequestHandler)
httpd.serve_forever()

Обратите внимание, что self.wfile является файлоподобным объектом, поэтому ожидает байтоподобных объектов для функции записи. Другой способ передать информацию в self.wfile - это использование объекта io.BytesIO.

from http.server import HTTPServer, BaseHTTPRequestHandler

from io import BytesIO


class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):

    # определяем метод `do_GET` 
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b'Hello, world!')

    # определяем метод `do_POST` 
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        body = self.rfile.read(content_length)
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        response = BytesIO()
        response.write(b'This is POST request. ')
        response.write(b'Received: ')
        response.write(body)
        self.wfile.write(response.getvalue())


httpd = HTTPServer(('localhost', 8000), SimpleHTTPRequestHandler)
httpd.serve_forever()

К телу запроса можно получить доступ через self.rfile. Это BufferedReader, поэтому для получения содержимого должен быть выполнен метод .read([size]). Обратите внимание, что функции должен быть явно передан размер, иначе запрос будет висеть и никогда не закончится.

Вот почему получение content_length необходимо. Он может быть извлечен через self.headers и преобразован в целое число. Пример выше просто печатает обратно все, что он получает.

Как завершить работу сервера Python?

Если сервер запускается через интерпретатор Python, например python3 myserver.py, просто нажмите Crtl+C.

Если необходимо элегантно закрыть его с помощью кода, то надо создать какое-либо условие, или точку, или исключение, для того, чтобы вызвать команду на выключение. Например можете добавить блок и вызвать httpd.shutdown() - так как сам класс HTTPServer является подклассом SocketServer.TCPServer. В свою очередь класс SocketServer.TCPServer является подклассом SocketServer.BaseServer у которого есть метод BaseServer.shutdown().

Из вышесказанного можно заключить то, что класс HttpServer так же будет имеет метод .shutdown(), как унаследованный от класса SocketServer.BaseServer.

import os
from http.server import SimpleHTTPRequestHandler, HTTPServer

os.chdir('c:/users/owner/desktop/pyserver')
server_address = ('', 8000)   
try:
    httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
    httpd.serve_forever()
except Exception:
    httpd.shutdown()

Метод httpd.shutdown() говорит серверу, что бы цикл httpd.serve_forever() остановился, при этом дождался завершения обработки запросов подключенных клиентов.