Chrome запрашивает блокировку

#python-3.x #http #tcpserver

#python-3.x #http #tcpserver

Вопрос:

Я сделал такой минимальный пример, который полностью повторяет поведение моего кода. Я делаю запросы из firefox и Chrome. Я заметил, что после выполнения запроса из chrome firefox перестает получать ответы. После некоторых исследований я понял, что сервер отвечает с ошибкой на localhost: запрос пути 8000/favicon.ico. Получив ошибку 404 один раз, chrome после каждого ответа от сервера создает другое соединение с сервером, но не отправляет данные, что вызывает блокировку функции recv.

   File "/usr/lib/python3.7/socket.py", line 589, in readinto
    return self._sock.recv_into(b)
  

Я обнаружил, что могу установить время ожидания соединения для класса обработчика, оно учитывается в StreamRequestHandler:r:

 if self.timeout is not None:
    self.connection.settimeout(self.timeout)
  

Но я смущен тем, что в документации нет информации об этом
https://docs.python.org/3/library/socketserver.html#socketserver.BaseRequestHandler.handle

 import logging
import json
import http.server
from http import HTTPStatus
from typing import Optional
from urllib.parse import urlparse, parse_qs
import socketserver
from threading import Thread
import traceback
from functools import wraps
import sys, os

project_dir = os.path.abspath(os.curdir)
sys.path.append(project_dir)


logging.getLogger().setLevel("DEBUG")


class RESTHandler(http.server.BaseHTTPRequestHandler):
    """
    Rest router for api methods
    """
    def __init__(self, *args, **kwargs):
        logging.info(f"Creating RESTHandler obj. Args: {args}, kwargs: {kwargs}")
        super().__init__(*args, **kwargs)
    
    def end_headers(self) -> None:
        self.send_header('Access-Control-Allow-Origin', '*')
        http.server.BaseHTTPRequestHandler.end_headers(self)

    # noinspection PyPep8Naming
    def do_GET(self):
        logging.info(self.path)
        url = urlparse(self.path)

        if "favicon.ico" in url.path:
            self.send_error(HTTPStatus.NOT_FOUND, message='Unknown api path.')
            return
        self.send_response(HTTPStatus.OK)
        self.send_header('Content-Type', 'application/json')
        self.end_headers()
        self.wfile.write(json.dumps({"resp":"I am OK", "int": 5}, ensure_ascii=False).encode('utf-8'))

class ApiService():

    DEFAULT_API_PORT = 8000
    DEFAULT_API_HOST = ''

    def __init__(self, ui_service = None, host: Optional[str] = None, port: Optional[int] = None):
        self.ui_service = ui_service
        self.host = host or self.DEFAULT_API_HOST
        self.port = port or self.DEFAULT_API_PORT

    def _run(self):
        while True:
            try:
                with socketserver.TCPServer((self.host, self.port), RESTHandler, bind_and_activate=False) as httpd:
                    logging.info("Starting server....")
                    httpd.allow_reuse_address = True
                    httpd.server_bind()
                    httpd.server_activate()
                    logging.info(f"Serving API at {self.host}:{self.port}")
                    httpd.serve_forever()
                    break
            except Exception as e:
                tb_list = traceback.format_exception( type(e), e, tb=e.__traceback__)
                tb_list = [ s.replace("n", "") for s in tb_list ]
                tb_str = "; ".join(tb_list)
                logging.error(f"Unexpected exception while http-server was working: {tb_str}")

    def run(self, in_thread=True):
        if in_thread:
            t = Thread(target=self._run)
            t.start()
        else:
            self._run()

if __name__ == '__main__':
    ApiService().run(in_thread=False)
  

Ответ №1:

Я предполагаю, что Chrome использует веб-браузеры, предварительно открывающие сокеты, на которых TCPServer будет ждать бесконечно в моем случае. Но мне все еще интересно, почему только после 404 и как насчет законности использования тайм-аута обработчика запроса.