用于aiohttp的会话管理websockets

aiohttp-session-ws的Python项目详细描述


https://travis-ci.org/dfee/aiohttp_session_ws.svg?branch=masterhttps://coveralls.io/repos/github/dfee/aiohttp_session_ws/badge.svg?branch=master

简单地说:将websockets与用户会话相关联,并在您认为合适时关闭这些连接。

例如,假设您正在使用aiohttp_security,用户选择登录或注销。 使用aiohttp_session_ws可以断开与其会话关联的打开的websocket订阅,并强制它们重新连接和授权该websocket订阅。

demo/demo.gif

基本示例

本例中的代码片段取自此存储库的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_idset_iddelete_id方法。

如果您有一个web服务器集群,则需要对SessionWSRegistry进行子类划分,并修改registerunregister函数,以便监听消息代理(例如,使用aioredis及其pubsub功能)。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java具有数量可变的参数,可以同时加载数量可变的图像   java应用程序在后台运行数小时后,当对象变量被系统破坏时,如何在应用程序类中保存对象变量   Java使用不带名称空间的XSD验证XML   关于在Play 2.2.1上安装死锁的java问题   字符串中的java字符串分隔符。分裂法   菜单中的java项不显示操作栏,而是在三个点中显示,没有任何图标   以int值作为键的java HashMap   java OpenAPIgeneratorEventPlugin身份验证查询参数未发送   java如何使用用户输入停止程序   java XIMA Formcycle图像预览问题   java Android登录MainActivity中的google   java Spring JPA@Query JPQL因“意外标记:日期”而失败   java如何将JTextField中的数据保存到mysql数据库中?   java jMonkeyEngine是否在网格内应用材质?   java传感器。键入旋转向量没有值?   java是一个从随机数序列中求值的简单算法吗?   java安卓8。x通知:当我的应用打开时,如何避免通过我的应用淡入/淡出通知?   java tomcat无法启动:严重:启动静态资源时出错   带有自定义列表的java Json操作警告