用于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第三方库


热门话题
JavaMaven没有识别junit测试   正则表达式替换Java中字符串中的所有“(“and”)”   文件移动到另一台计算机时出现java错误“实例化servlet类”   服务器上的java服务   Spring数据JPA上的java嵌套@Transactional注释行为   eclipse中的Java Tomcat项目   java在Tomcat上部署web应用程序   如何解决“java.lang.IllegalStateException:ArrayAdapter要求资源ID为TextView”错误?   java在条形码上方添加文本,并使用烧烤更改字体大小   java与php基准测试   java使用正则表达式提取特定模式   java扫描器。findInLine()大量泄漏内存   java HTTP:差异请求属性和POST参数   返回空指针的Java方法?   java验证密码不包含名称中的3个以上连续字符   Java中带泛型的静态多态性   java在Android中获得最后一个已知位置   java为什么Groovy的Map比Array更具可伸缩性?   编码如何在Java中生成八进制字符串?   java Hibernate:使用单例会话写入日志(无刷新)