用于aiohttp的会话管理websockets
aiohttp-session-ws的Python项目详细描述
简单地说:将websockets与用户会话相关联,并在您认为合适时关闭这些连接。
例如,假设您正在使用aiohttp_security,用户选择登录或注销。 使用aiohttp_session_ws可以断开与其会话关联的打开的websocket订阅,并强制它们重新连接和授权该websocket订阅。
基本示例
本例中的代码片段取自此存储库的demo目录。
asyncdefhandle_root(request):returnweb.Response(text='Hello world',content_type="text/html")asyncdefhandle_reset(request):session_ws_id=awaitget_session_ws_id(request)response=web.Response(text=f"Reset called on session {session_ws_id}!",content_type="text/plain",)awaitschedule_close_all_session_ws(request,response)awaitnew_session_ws_id(request)returnresponseasyncdefhandle_websocket(request):asyncwithsession_ws(request)aswsr:connected_at=datetime.now()session_ws_id=awaitget_session_ws_id(request)whileTrue:awaitwsr.send_str(f"Websocket associated with session [{session_ws_id}] "f"connected for {(datetime.now() - connected_at).seconds}")awaitasyncio.sleep(1)returnwsrdefmake_app():app=web.Application(middlewares=[aiohttp_session.session_middleware(aiohttp_session.SimpleCookieStorage()),session_ws_middleware,])app.router.add_get("/",handle_root)app.router.add_get("/reset",handle_reset)app.router.add_get("/ws",handle_websocket)setup_session_websockets(app,SessionWSRegistry())returnapp
使用demo文件夹中的代码,该文件夹包含一个简单的模板,用于在Web浏览器中与WebSocket交互。
叙述性API
这个软件包设计简单,易于使用。 这个轻量级文档并没有试图取代阅读代码的需要,所以我们鼓励您去做这件事。
有一些可移动的部分,但是如果(以及何时)您需要做一些更复杂的事情,您可以子类化。
SessionWSRegistry
这是aiohttp_session_ws的核心。
它的结构值得注意:
SessionWSRegistry(self, *, id_factory, session_key)
id_factory生成与WebSocket关联的会话范围ID。 默认id_工厂返回一个uuid4,但是您可以提供自己的可调用(也支持异步可调用)。 id_factory的函数签名是:
id_factory(request: aiohttp.web.Request) -> typing.Hashable
因此,返回一些可以作为字典中键的内容(字符串、整数等)。
session_key是会话中映射到会话范围websocket标识符的键的名称。 默认情况下,它是合理的aiohttp_session_ws_id。
助手
创建后不需要直接与SessionWSRegistry交互,但要知道它在aiohttp.web.Application中可用(按如下方式访问:app['aiohttp_session_ws_registry'])。
此对象的友好全局操纵器是:
- get_session_ws_id(request)
- new_session_ws_id(request)
- delete_session_ws_id(request)
- ensure_session_ws_id(request)
- schedule_close_all_session_ws(request, response)
这些方法可直接从aiohttp_session_ws导入。
注意,schedule_close_all_session_ws接受一个响应对象。 这允许我们结束响应的keep-alive状态(通过aiohttp.web.Response.force_close)。 这意味着一旦您的用户收到响应,他们未完成的websockets将关闭。
这也意味着,如果您有重新连接websockets的用户,您可能应该遵循以下模式:
asyncdefhandle_logout(request):response=web.HTTPFound('/')awaitschedule_close_all_session_ws(request,response)awaitaiohttp_session.new_session(request)awaitnew_session_ws_id(request)returnresponse
会话
要跟踪websockets,您将使用异步上下文管理器session_ws。 此上下文管理器升级请求,并提供其对应的aiothttp.web.WebSocketResponse。 如果喜欢,请使用:
asyncdefhandle_websocket(request):asyncwithsession_ws(request)aswsr:asyncformsginwsr:awaitwsr.send_str(f'Heard: {ws.data}')returnwsr
就这样。很简单,对吧? 如果要为aiohttp.web.WebSocketResponse提供初始化选项(例如,支持的websocket协议),请将这些选项作为命名参数传递给session_ws。
asyncdefhandle_websocket(request):asyncwithsession_ws(request,protocols=('graphql-ws',))aswsr:asyncformsginwsr:awaitwsr.send_str(f'Heard: {ws.data}')returnwsr
正如下面的notes中所提到的,在尝试WebSocket连接之前,您的用户拥有一个session_ws id是很重要的(提示:safari)。
使用session_ws_middleware自动将密钥添加到会话中。 它应该在aiohttp_session.session_middleware:
的调用堆栈中web.Application(middlewares=[aiohttp_session.session_middleware(aiohttp_session.SimpleCookieStorage()),session_ws_middleware,])
最后,要设置所有这些,您将需要使用setup方法(需要将其导入为setup_session_ws)。
基本用法如下:
web.Application(middlewares=[aiohttp_session.session_middleware(aiohttp_session.SimpleCookieStorage()),session_ws_middleware,])setup(app,SessionWSRegistry())# <------# etc...returnapp
注释
当session_ws在连接时生成aiohttp_session_ws_id时(如果它不存在的话),一些浏览器在WebSocket升级(例如Safari)时不尊重Set-Cookie。
因此,最好在尝试WebSocket连接之前确保用户会话中存在^{TT11}$(如果使用^{TT37}$或^{TT38}$)。
如果使用更高级的方法,在会话cookie中存储对会话的引用,并存储服务器端的实际值(如aiohttp_session.RedisStorage),则在cookie上设置aiohttp_session_ws_id时并不重要,但仍然很重要。t用户在尝试连接之前有会话cookie。
如果您想将会话ws-id(通常是aiohttp_session_ws_id)放在会话中的其他位置,或者从请求中派生它,则可以。 只需子类SessionWSRegistry并修改get_id、set_id和delete_id方法。
如果您有一个web服务器集群,则需要对SessionWSRegistry进行子类划分,并修改register和unregister函数,以便监听消息代理(例如,使用aioredis及其pubsub功能)。