HTTP-сервер Asyncio зависает с keepalive - PullRequest
0 голосов
/ 02 сентября 2018

Я пытаюсь написать сервер HTTP / 1, используя asyncio, и я пытаюсь заставить его обрабатывать HTTP keep-alive. У меня есть следующий фрагмент кода.

import re
import socket
import asyncio

async def request_handler(reader, writer):
    try:
        keep_alive = True

        while keep_alive:
            keep_alive = False

            while True:
                print('Awaiting data')
                line = await reader.readline()
                print('Finished await got %s' % line)
                if not line.rstrip(b'\r\n'):
                    break

                if re.match(rb'connection:\s*keep-alive', line, re.I):
                    keep_alive = True

            writer.write(b'HTTP/1.1 200 OK\r\n\r\n<h1>My web page</h1>\r\n')
            await writer.drain()
    finally:
        writer.close()

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    coro = asyncio.start_server(request_handler, '', 8888, family=socket.AF_UNSPEC, loop=loop, limit=2048)
    server = loop.run_until_complete(coro) 

    try:
        loop.run_forever()
    finally:
        server.close()
        loop.run_until_complete(server.wait_closed())
        loop.close()

С запросами от таких инструментов, как curl, запрос обрабатывается корректно без зависания сервера.

Однако попытка загрузить URL-адрес в браузере приводит к тому, что сервер никогда не прерывает соединение. Браузер пытается запросить два ресурса, один из которых /, а другой - /favicon.ico, и для запросов используются HTTP-сообщения поддержки активности. (Эту информацию можно увидеть с помощью инструментов разработчика.)

Я попытался распечатать данные, полученные сервером. Однако, похоже, сервер никогда не получает данные для второго запроса:

Awaiting data
Finished await got b'GET / HTTP/1.1\r\n'
Awaiting data
Finished await got b'Host: localhost:8888\r\n'
Awaiting data
Finished await got b'Connection: keep-alive\r\n'
Awaiting data
Finished await got b'Upgrade-Insecure-Requests: 1\r\n'
Awaiting data
Finished await got b'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36\r\n'
Awaiting data
Finished await got b'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n'
Awaiting data
Finished await got b'Accept-Encoding: gzip, deflate, br\r\n'
Awaiting data
Finished await got b'Accept-Language: en-US,en;q=0.9\r\n'
Awaiting data
Finished await got b'\r\n'
Awaiting data

Может кто-нибудь сказать мне, в чем проблема?

1 Ответ

0 голосов
/ 02 сентября 2018

При использовании Keep-Alive ответ должен содержать заголовок Content-Length (или использовать более сложную кодировку передачи chunked ). Без этого у клиента нет другого выбора, кроме как ждать, пока соединение не закроется, чего никогда не происходит, потому что keep_alive имеет значение true. Например, если вы измените код написания следующим образом:

            body = b'<h1>My web page</h1>\r\n'
            writer.write(b'HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n' % len(body))
            writer.write(body)

... соединение больше не прерывается.

curl работает, потому что не указывает Keep-Alive (поскольку в командной строке был указан только один URL-адрес), поэтому ваш код закрывает соединение и длина содержимого не требуется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...