在 K8s Ingress 后面使用 Falcon 和 Daphne 的 Websockets
Websockets with Falcon & Daphne behind a K8s Ingress
我的 Falcon based ASGI app is executed via Daphne 并且在 运行 本地并通过本地主机访问时工作正常。该应用程序被打包在一个容器中,运行 在 Ingress 后面的 K8s 集群中。在 K8s 上,应用程序不是 运行ning 在域的根目录中,而是在 /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,效果很好
daphne --root-path /sub/path ...
只要我只使用“正常”HTTP 请求。使用 websockets 失败。错误消息表明找不到路径,所以我假设我对根路径的剥离不起作用。我发现我是对的。有个特别的
async def process_request_ws(self, req, ws):
用于 websocket 连接。我试图完全按照 process_request
实现此方法,但 req.root_path
是空的。我没有在 req
中找到任何允许我删除前缀的值。
现在我想知道我是不是做错了什么,或者这是一个错误,应该设置 root_path
!?
这似乎是 Daphne 中的一个错误,WebSocket 的请求范围不包含 root_path
key/value.
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。
我的 Falcon based ASGI app is executed via Daphne 并且在 运行 本地并通过本地主机访问时工作正常。该应用程序被打包在一个容器中,运行 在 Ingress 后面的 K8s 集群中。在 K8s 上,应用程序不是 运行ning 在域的根目录中,而是在 /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,效果很好
daphne --root-path /sub/path ...
只要我只使用“正常”HTTP 请求。使用 websockets 失败。错误消息表明找不到路径,所以我假设我对根路径的剥离不起作用。我发现我是对的。有个特别的
async def process_request_ws(self, req, ws):
用于 websocket 连接。我试图完全按照 process_request
实现此方法,但 req.root_path
是空的。我没有在 req
中找到任何允许我删除前缀的值。
现在我想知道我是不是做错了什么,或者这是一个错误,应该设置 root_path
!?
这似乎是 Daphne 中的一个错误,WebSocket 的请求范围不包含 root_path
key/value.
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。