基于 Quart 的 restapi 中的 Asycio/hypercorn/SSL 错误,全部未处理

基于 Quart 的 restapi 中的 Asycio/hypercorn/SSL 错误,全部未处理

我正在用 quart 编写一个 restapi,由 Hypercorn 提供服务,使用由BenMorel 的剧本。我的单个 python 文件的结构如下:

import asyncio
from quart import Quart, request, abort, make_response, Response
from hypercorn.config import Config
from hypercorn.asyncio import serve

(...)
app = Quart(__name__)
(...)

@app.route(URL_BASE_PATH + "/get-stats", methods=['GET'])
async def getStats():
    (...)
    return {
        "query-able-first-date":firstDate,
        "query-able-last-date":lastDate,
        "free-space":freeSpace,
    }

(...)
if __name__ == '__main__':
try:
        config = Config()
        config.bind = ["0.0.0.0:" + str(SERVER_PORT)]

        if TLS_ENABLED:
            if os.path.isfile(TLS_CERT) and os.path.isfile(TLS_PRIVKEY):
                config.certfile = TLS_CERT
                config.keyfile = TLS_PRIVKEY
            else:
                print("TLS private key or certificate is missing, cannot use TLS")

        asyncio.run(serve(app, config))
    except Exception as e:
        print("Some error message")
        sys.exit(1)

如果我不使用 TLS,这一切都很好。但是,如果我使用 TLS,并在浏览器(Firefox 或 Chrome)中查找此页面,我会收到“一些”未处理的错误:

Task exception was never retrieved
future: <Task finished name='Task-6' coro=<worker_serve.<locals>._server_callback() done, defined at /home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/run.py:94> exception=SSLError(1, '[SSL: APPLICATION_DATA_AFTER_CLOSE_NOTIFY] application data after close notify (_ssl.c:2745)')>
Traceback (most recent call last):
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/tcp_server.py", line 70, in run
    await self._read_data()
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/tcp_server.py", line 106, in _read_data
    await self.protocol.handle(RawData(data))
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/protocol/__init__.py", line 62, in handle
    return await self.protocol.handle(event)
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/protocol/h2.py", line 188, in handle
    await self._handle_events(events)
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/protocol/h2.py", line 255, in _handle_events
    await self.streams[event.stream_id].handle(EndBody(stream_id=event.stream_id))
KeyError: 15

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/tcp_server.py", line 70, in run
    await self._read_data()
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/task_group.py", line 82, in __aexit__
    await task
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/task_group.py", line 78, in __aexit__
    await task
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/run.py", line 96, in _server_callback
    await TCPServer(app, loop, config, context, reader, writer)
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/tcp_server.py", line 74, in run
    await self._close()
  File "/home/sga/.local/lib/python3.9/site-packages/hypercorn/asyncio/tcp_server.py", line 118, in _close
    await self.writer.wait_closed()
  File "/usr/lib/python3.9/asyncio/streams.py", line 359, in wait_closed
    await self._protocol._get_close_waiter(self)
  File "/usr/lib/python3.9/asyncio/sslproto.py", line 528, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "/usr/lib/python3.9/asyncio/sslproto.py", line 206, in feed_ssldata
    self._sslobj.unwrap()
  File "/usr/lib/python3.9/ssl.py", line 948, in unwrap
    return self._sslobj.shutdown()
ssl.SSLError: [SSL: APPLICATION_DATA_AFTER_CLOSE_NOTIFY] application data after close notify (_ssl.c:2745)

因为我所做的只是在 asyncio 内部调用 hypercorn.serve,所以我对未处理的错误无能为力...在 Firefox 中,我导入了假的自签名证书并得到了 Keyerror: 15,而在 chrome 中我没有(只是接受了非常有害的后果)我得到了 Keyerror: 1。除此之外,作为客户端,两种浏览器都会发生相同的错误。

我知道这个 SSL 错误意味着服务器在关闭 SSL 连接后才收到数据,但我不知道为什么会发生这种情况。我还看到 asyncio 失败,因此给出“CancelledError”消息……尽管应用程序和 restapi 服务器继续运行,我甚至在浏览器中得到了结果。我不明白如何解决这个问题,或者从哪里开始调试它。

答案1

看起来这个问题只发生在网络浏览器上。使用最新的 curl(支持 HTTP/2),如果我询问页面(curl -kv --http https://IP:port/resource),它工作正常……

相关内容