Модуль 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.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.server.BaseHTTPRequestHandler()
- класс используется для обработки HTTP-запросов, поступающих на сервер;http.server.SimpleHTTPRequestHandler()
- обслуживает файлы из текущего каталога, напрямую сопоставляя структуру каталогов с HTTP-запросами;http.server.CGIHTTPRequestHandler()
- обслуживает файлы или вывод сценариев CGI из текущего каталога.Пример HTTP web-сервера, обрабатывающего статические файлы.
python3 -m http.server 8000 --bind 127.0.0.1
Если запустить HTTP сервер таким способом, то можно создать, например, фиктивный API путем загрузки на этот сервер статических файлов json
или/и xml
. Структура ресурсов файлов, организованных в подпапки, будет обеспечивать RESTful-подобные URL-адреса. Например, /users/all.json
может содержать фиктивные записи пользователей. Этот подход еще быстрее, чем создание, например, приложения Flask
. База данных не требуется, работает везде. Можно применять там, где например есть некоторые трудности с командой терминала scp
для загрузки данных. Решение - можно запустить простой сервер на удаленной машине и загрузить необходимое содержимое через HTTP.
Для запуска защищенного 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-сервера, который отвечает 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, например 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()
остановился, при этом дождался завершения обработки запросов подключенных клиентов.