在一个基于FastAPI的Web应用程序中,我有一个WebSocket端点,它应该仅在满足某些条件时才允许连接,否则它应该返回HTTP 404
回复,而不是使用HTTP 101
升级连接。
据我所知,这是完全支持的协议,但我找不到任何方法来做它与FastAPI或Starlette.
如果我有这样的东西:
@router.websocket("/foo")
async def ws_foo(request: WebSocket):
if _user_is_allowed(request):
await request.accept()
_handle_ws_connection(request)
else:
raise HTTPException(status_code=404)
该异常不会转换为404响应,因为FastAPI的ExceptionMiddleware
似乎无法处理此类情况。
是否有任何本地/内置的方式来支持这种“拒绝”流?
1条答案
按热度按时间vlurs2pr1#
一旦握手完成,protocol changes from
HTTP
toWebSocket
。如果您试图在WebSocket端点内引发HTTP
异常,您会发现这是不可能的,或者返回HTTP
响应(例如,return JSONResponse(...status_code=404)
),您会得到一个内部服务器错误,即ASGI callable returned without sending handshake
。选项1
因此,如果您希望在协议升级之前有某种检查机制,则需要使用
Middleware
,如下所示:在中间件内部,您不能引发异常,但可以返回响应(即Response
、JSONResponse
、PlainTextResponse
等),这实际上是FastAPI在后台处理异常的方式。作为参考,请看一下这个post,以及讨论here。或者,如果愿意,可以让
is_user_allowed()
方法引发一个需要用try-except
块捕获的自定义异常:选项2
但是,如果需要使用
websocket
示例来执行此操作,则可以使用与上面相同的逻辑,但要改为在is_user_allowed()
方法中传递websocket
示例,并在WebSocket端点内捕获异常(受this启发)。但是,在上面的代码中,你必须首先接受连接,这样如果出现异常,你就可以调用
close()
方法来终止连接。如果你愿意,你可以使用类似下面的代码。但是,except
块中的return
语句会引发一个内部服务器错误(即ASGI callable returned without sending handshake.
),如前所述。