21.22. http.server – HTTP-серверы¶http.server – HTTP servers
Исходный код: Lib/http/server.py
Этот модуль определяет классы для реализации HTTP-серверов (веб-серверов).
Один класс, 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()
- class http.server.HTTPServer(server_address, RequestHandlerClass)¶
Этот класс расширяет класс TCPServer, сохраняя адрес сервера в переменных экземпляра server_name и server_port. Сервер доступен обработчику, обычно через переменную экземпляра server обработчика.
При создании экземпляра HTTPServer необходимо передать RequestHandlerClass, для которого этот модуль предоставляет три различных варианта:
- class http.server.BaseHTTPRequestHandler(request, client_address, server)¶
Этот класс используется для обработки HTTP-запросов, поступающих на сервер. Сам по себе он не может отвечать на реальные HTTP-запросы; его нужно наследовать, чтобы обрабатывать каждый метод запроса (например, GET или POST). BaseHTTPRequestHandler предоставляет ряд переменных класса и экземпляра, а также методы для использования подклассами.
Обработчик разбирает запрос и заголовки, затем вызывает метод, соответствующий типу запроса. Имя метода формируется из запроса. Например, для метода запроса SPAM будет вызван метод do_SPAM() без аргументов. Вся соответствующая информация хранится в переменных экземпляра обработчика. Подклассы не должны переопределять или расширять метод __init__().
BaseHTTPRequestHandler имеет следующие переменные экземпляра:
- client_address¶
Содержит кортеж вида (host, port), относящийся к адресу клиента.
- server¶
Содержит экземпляр сервера.
- close_connection¶
Логическое значение, которое должно быть установлено до возврата handle_one_request(), указывающее, ожидается ли ещё один запрос или соединение должно быть закрыто.
- requestline¶
Содержит строковое представление строки HTTP-запроса. Завершающие символы CRLF удаляются. Этот атрибут должен устанавливаться методом handle_one_request(). Если ни одна корректная строка запроса не была обработана, он должен быть установлен в пустую строку.
- command¶
Содержит команду (тип запроса). Например, 'GET'.
- path¶
Содержит путь запроса.
- request_version¶
Содержит строку версии из запроса. Например, 'HTTP/1.0'.
- headers¶
Содержит экземпляр класса, указанного переменной класса MessageClass. Этот экземпляр разбирает и управляет заголовками в HTTP-запросе. Функция parse_headers() из http.client используется для разбора заголовков, и она требует, чтобы HTTP-запрос содержал корректный заголовок в стиле RFC 2822.
- rfile¶
Содержит входной поток, находящийся в начале необязательных входных данных.
- wfile¶
Содержит выходной поток для записи ответа обратно клиенту. При записи в этот поток необходимо строго соблюдать протокол HTTP.
BaseHTTPRequestHandler имеет следующие переменные класса:
- server_version¶
Указывает версию серверного программного обеспечения. Возможно, потребуется переопределить это значение. Формат – несколько строк, разделённых пробелами, где каждая строка имеет вид имя[/версия]. Например, 'BaseHTTP/0.2'.
- sys_version¶
Содержит версию системы Python в форме, пригодной для использования методом version_string и переменной класса server_version. Например, 'Python/1.4'.
- error_message_format¶
Задаёт строку форматирования для построения ответа об ошибке клиенту. В ней используются указатели формата в скобках с ключами, поэтому операнд формата должен быть словарём. Ключ code должен быть целым числом, задающим числовой код ошибки HTTP. message должен быть строкой, содержащей (подробное) сообщение об ошибке, а explain – объяснением кода ошибки. Значения по умолчанию для message и explain находятся в переменной класса responses.
- error_content_type¶
Задаёт HTTP-заголовок Content-Type для ответов об ошибках, отправляемых клиенту. Значение по умолчанию: 'text/html'.
- protocol_version¶
Задаёт версию протокола HTTP, используемую в ответах. Если установлено 'HTTP/1.1', сервер будет разрешать постоянные соединения; однако в этом случае сервер должен включать точный заголовок Content-Length (с помощью send_header()) во все свои ответы клиентам. Для обратной совместимости по умолчанию используется 'HTTP/1.0'.
- MessageClass¶
Задаёт класс, похожий на email.message.Message, для разбора HTTP-заголовков. Обычно его не переопределяют, и по умолчанию используется http.client.HTTPMessage.
- responses¶
Эта переменная содержит отображение целочисленных кодов ошибок в кортежи из двух элементов, содержащие краткое и полное сообщения. Например, {code: (shortmessage, longmessage)}. shortmessage обычно используется как ключ message в ответе об ошибке, а longmessage – как ключ explain (см. переменную класса error_message_format).
Экземпляр BaseHTTPRequestHandler имеет следующие методы:
- handle()¶
Вызывает handle_one_request() один раз (или несколько, если включены постоянные соединения) для обработки входящих HTTP-запросов. Этот метод не нужно переопределять; вместо этого следует реализовать соответствующие методы do_*().
- handle_one_request()¶
Этот метод разбирает запрос и направляет его в соответствующий метод do_*(). Его не нужно переопределять.
- handle_expect_100()¶
Когда сервер, совместимый с HTTP/1.1, получает заголовок запроса Expect: 100-continue, он отвечает заголовками 100 Continue, а затем 200 OK. Этот метод можно переопределить, чтобы вызвать ошибку, если сервер не хочет, чтобы клиент продолжал. Например, сервер может отправить 417 Expectation Failed в качестве заголовка ответа и return False.
Новое в версии 3.2.
- send_error(code, message=None, explain=None)¶
Отправляет и журналирует полный ответ об ошибке клиенту. Числовой code задаёт код ошибки HTTP, а message – необязательное краткое, понятное человеку описание ошибки. Аргумент explain можно использовать для предоставления более подробной информации об ошибке; он будет отформатирован с помощью переменной класса error_message_format и отправлен после полного набора заголовков как тело ответа. Переменная класса responses содержит значения по умолчанию для message и explain, которые используются, если не указано иное; для неизвестных кодов по умолчанию для обоих используется строка ???.
Изменено в версии 3.4: Ответ об ошибке включает заголовок Content-Length. Добавлен аргумент explain.
- send_response(code, message=None)¶
Добавляет заголовок ответа в буфер заголовков и журналирует принятый запрос. Строка ответа HTTP записывается во внутренний буфер, за ней следуют заголовки Server и Date. Значения для этих двух заголовков берутся из методов version_string() и date_time_string() соответственно. Если сервер не собирается отправлять другие заголовки с помощью метода send_header(), то после send_response() должен следовать вызов end_headers().
Изменено в версии 3.3: Заголовки сохраняются во внутренний буфер, и end_headers() требуется вызывать явно.
- send_header(keyword, value)¶
Добавляет HTTP-заголовок во внутренний буфер, который будет записан в выходной поток при вызове end_headers() или flush_headers(). keyword задаёт ключевое слово заголовка, а value – его значение. Обратите внимание: после выполнения всех вызовов send_header end_headers() ДОЛЖЕН быть вызван для завершения операции.
Изменено в версии 3.2: Заголовки сохраняются во внутреннем буфере.
- send_response_only(code, message=None)¶
Отправляет только заголовок ответа; используется, когда сервер отправляет клиенту ответ 100 Continue. Заголовки не буферизуются и отправляются напрямую в выходной поток. Если message не указан, отправляется HTTP-сообщение, соответствующее коду ответа code.
Новое в версии 3.2.
- end_headers()¶
Добавляет пустую строку (означающую конец HTTP-заголовков в ответе) в буфер заголовков и вызывает flush_headers().
Изменено в версии 3.2: Буферизированные заголовки записываются в выходной поток.
- flush_headers()¶
Наконец отправляет заголовки в выходной поток и очищает внутренний буфер заголовков.
Новое в версии 3.3.
- log_request(code='-', size='-')¶
Записывает в журнал принятый (успешный) запрос. Параметр code должен задавать числовой код HTTP, связанный с ответом. Если размер ответа доступен, его следует передать как параметр size.
- log_error(...)¶
Журналирует ошибку, если запрос не может быть выполнен. По умолчанию передаёт сообщение в log_message(), поэтому принимает те же аргументы (format и дополнительные значения).
- log_message(format, ...)¶
Записывает произвольное сообщение в sys.stderr. Обычно этот метод переопределяют для создания собственных механизмов регистрации ошибок. Аргумент format – это стандартная printf-строка форматирования, к которой дополнительные аргументы log_message() применяются как входные данные для форматирования. IP-адрес клиента и текущие дата и время добавляются в начало каждого сообщения.
- version_string()¶
Возвращает строку версии серверного ПО. Она представляет собой комбинацию классовых переменных server_version и sys_version.
- date_time_string(timestamp=None)¶
Возвращает дату и время, заданные timestamp (который должен быть None или в формате, возвращаемом time.time()), отформатированные для заголовка сообщения. Если timestamp опущен, используются текущие дата и время.
Результат выглядит как 'Sun, 06 Nov 1994 08:49:37 GMT'.
- log_date_time_string()¶
Возвращает текущие дату и время, отформатированные для логирования.
- address_string()¶
Возвращает адрес клиента.
Изменено в версии 3.3: Ранее выполнялся поиск по имени. Чтобы избежать задержек разрешения имён, теперь всегда возвращается IP-адрес.
- class http.server.SimpleHTTPRequestHandler(request, client_address, server)¶
Этот класс обслуживает файлы из текущего каталога и подкаталогов, напрямую отображая структуру каталогов на HTTP-запросы.
Большая часть работы, такая как разбор запроса, выполняется базовым классом BaseHTTPRequestHandler. Этот класс реализует функции do_GET() и do_HEAD().
Следующие атрибуты определены как атрибуты класса SimpleHTTPRequestHandler:
- server_version¶
Это будет "SimpleHTTP/" + __version__, где __version__ определена на уровне модуля.
- extensions_map¶
Словарь, сопоставляющий расширения с MIME-типами. Значение по умолчанию обозначается пустой строкой и считается равным application/octet-stream. Сопоставление используется без учёта регистра, поэтому должно содержать только ключи в нижнем регистре.
Класс SimpleHTTPRequestHandler определяет следующие методы:
- do_HEAD()¶
This method serves the 'HEAD' request type: it sends the headers it would send for the equivalent GET request. See the do_GET() method for a more complete explanation of the possible headers.
- do_GET()¶
Запрос сопоставляется с локальным файлом путём интерпретации запроса как пути относительно текущего рабочего каталога.
Если запрос был сопоставлен с каталогом, то в нём ищется файл с именем index.html или index.htm (именно в таком порядке). Если файл найден, возвращается его содержимое; в противном случае формируется список содержимого каталога вызовом метода list_directory(). Этот метод использует os.listdir() для просмотра каталога и возвращает ответ с ошибкой 404, если listdir() завершается неудачей.
Если запрос был сопоставлен с файлом, он открывается и возвращается его содержимое. Любое исключение OSError при открытии запрошенного файла преобразуется в ошибку 404, 'File not found'. В противном случае тип содержимого определяется вызовом метода guess_type(), который, в свою очередь, использует переменную extensions_map.
Выводится заголовок 'Content-type:' с определённым типом содержимого, затем заголовок 'Content-Length:' с размером файла и заголовок 'Last-Modified:' с временем изменения файла.
Затем идёт пустая строка, обозначающая конец заголовков, а затем выводится содержимое файла. Если MIME-тип файла начинается с text/, файл открывается в текстовом режиме; в противном случае используется двоичный режим.
Пример использования см. в реализации вызова функции test() в модуле http.server.
Класс SimpleHTTPRequestHandler можно использовать следующим образом для создания самого простого веб-сервера, раздающего файлы из текущего каталога:
import http.server
import socketserver
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()
http.server можно также запустить напрямую, используя ключ -m интерпретатора с аргументом порт номер. Как и в предыдущем примере, он раздаёт файлы из текущего каталога:
python -m http.server 8000
По умолчанию сервер привязывается ко всем интерфейсам. Опция -b/--bind задаёт конкретный адрес, к которому он должен привязываться. Например, следующая команда заставляет сервер привязываться только к localhost:
python -m http.server 8000 --bind 127.0.0.1
Новое в версии 3.4: --bind аргумент был добавлен.
- class http.server.CGIHTTPRequestHandler(request, client_address, server)¶
Этот класс используется для обслуживания файлов или вывода CGI-скриптов из текущего каталога и всех подкаталогов. Обратите внимание, что сопоставление иерархической структуры HTTP с локальной файловой структурой производится точно так же, как в SimpleHTTPRequestHandler.
Примечание
CGI-скрипты, запускаемые классом CGIHTTPRequestHandler, не могут выполнять перенаправления (HTTP-код 302), поскольку код 200 (за которым следует вывод скрипта) отправляется до выполнения CGI-скрипта. Это заменяет код состояния.
Однако класс будет запускать CGI-скрипт вместо того, чтобы отдавать его как файл, если он определит, что это CGI-скрипт. Используются только каталогизированные CGI – другая распространённая конфигурация сервера (обработка специальных расширений как обозначающих CGI-скрипты) не применяется.
Функции do_GET() и do_HEAD() изменены для запуска CGI-скриптов и выдачи их результатов вместо файлов, если запрос ведёт к пути, расположенному внутри cgi_directories.
CGIHTTPRequestHandler определяет следующий атрибут данных:
- cgi_directories¶
По умолчанию это значение равно ['/cgi-bin', '/htbin'] и определяет каталоги, которые считаются содержащими CGI-скрипты.
CGIHTTPRequestHandler определяет следующий метод:
- do_POST()¶
Этот метод обрабатывает запросы типа 'POST', разрешённые только для CGI скриптов. При попытке отправить POST на не-CGI URL выводится ошибка 501 «Can only POST to CGI scripts».
Обратите внимание: из соображений безопасности CGI-скрипты будут запускаться с UID пользователя nobody. Проблемы с CGI-скриптом приведут к ошибке 403.
CGIHTTPRequestHandler можно активировать из командной строки, указав параметр --cgi:
python -m http.server --cgi 8000