【问题标题】:Websockets with Falcon & Daphne behind a K8s IngressK8s Ingress 背后的 Falcon 和 Daphne 的 Websockets
【发布时间】:2021-11-22 16:26:40
【问题描述】:

我的基于 Falcon 的 ASGI 应用程序通过 Daphne 执行,并且在本地运行并通过 localhost 访问时工作正常。该应用程序打包在一个容器中,并在 Ingress 后面的 K8s 集群中运行。在 K8s 上,应用程序不是在域的根目录中运行,而是在 /sub/folder 中运行。这打破了猎鹰的路线。我找不到现有的中间件,所以我实现了一个:

class StripRootPath:
    async def process_request(self, req, resp):
        root_path = req.root_path
        if root_path:
            req.path = req.path[len(root_path) :]

如果我这样称呼达芙妮,这很好用

daphne --root-path /sub/path ...

只要我只使用“正常”的 HTTP 请求。使用 websockets 失败。错误消息表明找不到路径,所以我认为我对根路径的剥离不起作用。我发现我是对的。有一个特殊的

async def process_request_ws(self, req, ws):

用于 websocket 连接。我尝试完全按照process_request 实现此方法,但req.root_path 为空。我在req 中没有找到任何可以让我去掉前缀的值。

现在我想知道我是否做错了什么,或者这是一个错误,应该设置root_path!?

【问题讨论】:

    标签: python websocket daphne falconframework asgi


    【解决方案1】:

    这似乎是 Daphne 的一个错误,WebSocket 的请求范围不包含 root_path 键/值。

    process_request_ws 通过修改req.path 可以很好地在内部重定向,但是,我只是在我的概念验证test.py 中硬编码了前缀:

    import falcon
    import falcon.asgi
    
    
    class InternalRedirect:
        async def process_request(self, req, resp):
            print(f'req.path={req.path}; req.root_path={req.root_path}')
            if req.path.startswith('/root/'):
                req.path = req.path.split('/root', 1)[1]
    
        async def process_request_ws(self, req, ws):
            print(f'req.path={req.path}; req.root_path={req.root_path}')
            if req.path.startswith('/root/'):
                req.path = req.path.split('/root', 1)[1]
    
    
    class HelloResource:
        async def on_get(self, req, resp, name):
            resp.media = {'message': f'Hello, {name}!'}
    
        async def on_websocket(self, req, ws, name):
            try:
                await ws.accept()
                await ws.send_media({'message': f'Hello, {name}'})
    
                while True:
                    payload = await ws.receive_text()
                    print(f'Received: [{payload}])')
            except falcon.WebSocketDisconnected:
                pass
    
    
    app = falcon.asgi.App(middleware=[InternalRedirect()])
    app.add_route('/hello/{name}', HelloResource())
    

    我尝试在Uvicorn 中运行相同的应用程序,而root_path 既适用于普通的GET 请求,也适用于升级到WebSocket:

    $ uvicorn --root-path /root test:app
    
    ...
    
    INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
    req.path=/root/hello/robot; req.root_path=/root
    INFO:     ('127.0.0.1', 33776) - "WebSocket /root/root/hello/robot" [accepted]
    INFO:     connection open
    INFO:     connection closed
    

    OTOH,甚至 Uvicorn 的日志也说明了(注意双重 /root/root)在 ASGI 中围绕 root_path 的混乱;与 WSGI 的 SCRIPT_NAME 相反,尚不清楚 ASGI path 是否应该包含它。 另见:

    尽管存在混乱,Uvicorn 应该可以解决您手头的问题。此外,它是目前最受欢迎和性能最好的 ASGI 应用服务器之一,所以我建议的解决方案是尝试将 Daphne 换成 Uvicorn。

    【讨论】:

      猜你喜欢
      • 2020-11-06
      • 2020-06-09
      • 2022-06-29
      • 1970-01-01
      • 2020-11-10
      • 2021-12-14
      • 2022-06-29
      • 2019-07-29
      • 2019-03-24
      相关资源
      最近更新 更多