Автор оригинала: Doug Hellmann.
Цель:
http.server включает классы, которые могут составлять основу веб сервер.
http.server
использует классы из socketserver для создания базовых классов для создания HTTP-серверов. HTTPServer
можно использовать напрямую, но BaseHTTPRequestHandler
предназначен для расширения для обработки каждого метода протокола (GET, POST и т. д.).
HTTP GET
Чтобы добавить поддержку метода HTTP в класс обработчика запросов, реализуйте метод do_METHOD ()
, заменив METHOD
на имя метода HTTP (например, do_GET ()
, do_POST ()
и т. д.). Для согласованности методы обработчика запросов не принимают аргументов. Все параметры запроса анализируются BaseHTTPRequestHandler
и сохраняются как атрибуты экземпляра экземпляра запроса.
В этом примере обработчика запросов показано, как вернуть ответ клиенту, а также некоторые локальные атрибуты, которые могут быть полезны при построении ответа.
http_server_GET.py
from http.server import BaseHTTPRequestHandler from urllib import parse class GetHandler(BaseHTTPRequestHandler): def do_GET(self): parsed_path parse.urlparse(self.path) message_parts [ 'CLIENT VALUES:', {} ({})'.format( self.client_address, self.address_string()), {}'.format(self.command), {}'.format(self.path), 'real>{}'.format(parsed_path.path), {}'.format(parsed_path.query), {}'.format(self.request_version), '', 'SERVER VALUES:', {}'.format(self.server_version), {}'.format(self.sys_version), {}'.format(self.protocol_version), '', 'HEADERS RECEIVED:', ] for name, value in sorted(self.headers.items()): message_parts.append( '{}{}'.format(name, value.rstrip()) ) message_parts.append('') message '\r\n'.join(message_parts) self.send_response(200) self.send_header('Content-Type', 'text/plain;) self.end_headers() self.wfile.write(message.encode('utf-8')) if __name__ '__main__': from http.server import HTTPServer server HTTPServer(('localhost', 8080), GetHandler) print('Starting server, useto stop') server.serve_forever()
Текст сообщения собирается и затем записывается в wfile
, дескриптор файла, охватывающий сокет ответа. Для каждого ответа требуется код ответа, установленный с помощью send_response ()
. Если используется код ошибки (404, 501 и т. Д.), Соответствующее сообщение об ошибке по умолчанию включается в заголовок, или сообщение может быть передано с кодом ошибки.
Чтобы запустить обработчик запросов на сервере, передайте его конструктору HTTPServer
, как в части обработки __main__
в примере сценария.
Затем запустите сервер:
$ python3 http_server_GET.py Starting server, useto stop
В отдельном терминале используйте curl
для доступа к нему:
$ curl -v -i * Trying 127.0.0.1... * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) > GET > Host: 127.0.0.1:8080 > User-Agent: curl/7.43.0 > Accept: */* > HTTP/1.0 200 OK Content-Type: text/plain; Server: BaseHTTP/0.6 Python/3.5.2 Date: Thu, 06 Oct 2016 20:44:11 GMT CLIENT VALUES: client_address=('127.0.0.1', 52934) (127.0.0.1) real path=/ SERVER VALUES: HEADERS RECEIVED: * Connection #0 to host 127.0.0.1 left intact
Примечание
Вывод, производимый разными версиями curl
, может отличаться. Если выполнение примеров дает другой результат, проверьте номер версии, указанный curl
.
HTTP POST
Поддержка запросов POST – это немного больше работы, потому что базовый класс не анализирует данные формы автоматически. Модуль cgi
предоставляет класс FieldStorage
, который знает, как анализировать форму, если ей заданы правильные входные данные.
http_server_POST.py
import cgi from http.server import BaseHTTPRequestHandler import io class PostHandler(BaseHTTPRequestHandler): def do_POST(self): # Parse the form data posted form cgi.FieldStorage( fpself.rfile, headersself.headers, environ{ 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers['Content-Type'], } ) # Begin the response self.send_response(200) self.send_header('Content-Type', 'text/plain;) self.end_headers() out io.TextIOWrapper( self.wfile, encoding'utf-8', line_bufferingFalse, write_throughTrue, ) out.write('Client: {}\n'.format(self.client_address)) out.write('User-agent: {}\n'.format( self.headers['user-agent'])) out.write('Path: {}\n'.format(self.path)) out.write('Form data:\n') # Echo back information about what was posted in the form for field in form.keys(): field_item form[field] if field_item.filename: # The field contains an uploaded file file_data field_item.file.read() file_len len(file_data) del file_data out.write( '\tUploaded {} as {!r} ({} bytes)\n'.format( field, field_item.filename, file_len) ) else: # Regular form value out.write('\t{}{}\n'.format( field, form[field].value)) # Disconnect our encoding wrapper from the underlying # buffer so that deleting the wrapper doesn't close # the socket, which is still being used by the server. out.detach() if __name__ '__main__': from http.server import HTTPServer server HTTPServer(('localhost', 8080), PostHandler) print('Starting server, useto stop') server.serve_forever()
Запускаем сервер в одном окне:
$ python3 http_server_POST.py Starting server, useto stop
Аргументы для curl
могут включать данные формы, которые будут отправлены на сервер с помощью параметра -F
. Последний аргумент, -F
, отправляет содержимое файла http_server_GET.py
для иллюстрации чтения данных файла из формы.
$ curl -v http://127.0.0.1:8080/ -F -F * Trying 127.0.0.1... * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) > POST / HTTP/1.1 > Host: 127.0.0.1:8080 > User-Agent: curl/7.43.0 > Accept: */* > Content-Length: 1974 > Expect: 100-continue > Content-Type: multipart/form-data; > * Done waiting for 100-continue HTTP/1.0 200 OK Content-Type: text/plain; Server: BaseHTTP/0.6 Python/3.5.2 Date: Thu, 06 Oct 2016 20:53:48 GMT Client: ('127.0.0.1', 53121) User-agent: curl/7.43.0 Path: / Form data: Uploaded datafile as 'http_server_GET.py' (1612 bytes) * Connection #0 to host 127.0.0.1 left intact
Заправка и разветвление
HTTPServer
– это простой подкласс socketserver.TCPServer
, который не использует несколько потоков или процессов для обработки запросов. Чтобы добавить потоки или разветвление, создайте новый класс, используя соответствующее соединение с сервера сокетов.
http_server_threads.py
from http.server import HTTPServer, BaseHTTPRequestHandler from socketserver import ThreadingMixIn import threading class Handler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header('Content-Type', 'text/plain;) self.end_headers() message threading.currentThread().getName() self.wfile.write(message.encode('utf-8')) self.wfile.write(b'\n') class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """Handle requests in a separate thread.""" if __name__ '__main__': server ThreadedHTTPServer(('localhost', 8080), Handler) print('Starting server, useto stop') server.serve_forever()
Запустите сервер так же, как в других примерах.
$ python3 http_server_threads.py Starting server, useto stop
Каждый раз, когда сервер получает запрос, он запускает новый поток или процесс для его обработки:
$ curl http://127.0.0.1:8080/ Thread-1 $ curl http://127.0.0.1:8080/ Thread-2 $ curl http://127.0.0.1:8080/ Thread-3
Замена ForkingMixIn
на ThreadingMixIn
приведет к аналогичным результатам, используя отдельные процессы вместо потоков.
Обработка ошибок
Обрабатывайте ошибки, вызывая send_error ()
, передавая соответствующий код ошибки и необязательное сообщение об ошибке. Полный ответ (с заголовками, кодом состояния и телом) создается автоматически.
http_server_errors.py
from http.server import BaseHTTPRequestHandler class ErrorHandler(BaseHTTPRequestHandler): def do_GET(self): self.send_error(404) if __name__ '__main__': from http.server import HTTPServer server HTTPServer(('localhost', 8080), ErrorHandler) print('Starting server, useto stop') server.serve_forever()
В этом случае всегда возвращается ошибка 404.
$ python3 http_server_errors.py Starting server, useto stop
Сообщение об ошибке передается клиенту с использованием HTML-документа, а также заголовка для указания кода ошибки.
$ curl -i http://127.0.0.1:8080/ HTTP/1.0 404 Not Found Server: BaseHTTP/0.6 Python/3.5.2 Date: Thu, 06 Oct 2016 20:58:08 GMT Connection: close Content-Type: Content-Length: 447Error response Error response
Error code: 404
Message: Not Found.
Error code explanation: 404 - Nothing matches the given URI.
Установка заголовков
Метод send_header
добавляет данные заголовка в ответ HTTP. Он принимает два аргумента: имя заголовка и значение.
http_server_send_header.py
from http.server import BaseHTTPRequestHandler import time class GetHandler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header( 'Content-Type', 'text/plain;, ) self.send_header( 'Last-Modified', self.date_time_string(time.time()) ) self.end_headers() self.wfile.write('Response body\n'.encode('utf-8')) if __name__ '__main__': from http.server import HTTPServer server HTTPServer(('localhost', 8080), GetHandler) print('Starting server, useto stop') server.serve_forever()
В этом примере в заголовке Last-Modified
устанавливается текущая отметка времени, отформатированная в соответствии с RFC 7231.
$ curl -i http://127.0.0.1:8080/ HTTP/1.0 200 OK Server: BaseHTTP/0.6 Python/3.5.2 Date: Thu, 06 Oct 2016 21:00:54 GMT Content-Type: text/plain; Last-Modified: Thu, 06 Oct 2016 21:00:54 GMT Response body
Сервер записывает запрос в терминал, как и в других примерах.
$ python3 http_server_send_header.py Starting server, useto stop 127.0.0.1 - - [06/Oct/2016 17:00:54] "GET / HTTP/1.1" 200 -
Использование командной строки
http.server
включает встроенный сервер для обслуживания файлов из локальной файловой системы. Запустите его из командной строки с помощью параметра -m
для интерпретатора Python.
$ python3 -m http.server 8080 Serving HTTP on 0.0.0.0 port 8080 ... 127.0.0.1 - - [06/Oct/2016 17:12:48] "HEAD /index.rst HTTP/1.1" 200 -
Корневой каталог сервера – это рабочий каталог, в котором запущен сервер.
$ curl -I http://127.0.0.1:8080/index.rst HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/3.5.2 Date: Thu, 06 Oct 2016 21:12:48 GMT Content-type: application/octet-stream Content-Length: 8285 Last-Modified: Thu, 06 Oct 2016 21:12:10 GMT
Смотрите также
- стандартная библиотечная документация для http.server
- socketserver – модуль
socketserver
предоставляет базовый класс, который обрабатывает необработанное соединение сокета. - RFC 7231 – «Протокол передачи гипертекста (HTTP/1.1): семантика и содержание» включает спецификацию формата заголовков и дат HTTP.