[关闭]
@gzm1997 2018-06-13T16:54:34.000000Z 字数 3121 阅读 1858

aiohttp session

aiohttp session


cookie和session

服务端和客户端之间的联系一般是根据http协议来进行的 但是http协议是无状态的 无状态会有状态的概念大概如下

有状态

  1. 甲:你吃午饭了吗
  2. 乙:吃了
  3. 甲:吃了什么菜
  4. 乙:吃了鸡蛋

无状态

  1. 甲:你吃午饭了吗
  2. 乙:吃了
  3. 甲:吃了什么菜
  4. 乙:你说什么时候吃什么菜 早饭?午饭?还是晚饭

因此服务端和客户端之间需要一种机制来记录用户的状态 这种机制在客户端那边是cookies 在服务端那边是session
cookies可以存储在磁盘 内存里面 session可以存储在内存 缓存 redis甚至磁盘中


aiohttp session

flask框架具有内置的session机制 我以前用起来觉得非常方便以至于我觉得这个不重要 aiohttp不具有内置的session机制 但是具有第三方模块支持 aiohttp_session

安装这个第三方模块真的挺费事 因为依赖模块实在太多了 而且aiohttp_session是可以依赖redis作为缓存的 还需要安装redis和一些相关模块 下面的开始的实例我没有使用redis作为存储位置 而是使用了EncryptedCookieStorage 后面附加了使用redis存储session的例子

dependencies

安装模块


存储位置选择

所有仓库是使用名为AIOHTTP_COOKIE_SESSION的对象来进行存储数据的

可以使用的仓库有


使用

使用上跟flask的session大同小异 但是需要在init app阶段将session安装到app上 设定一个32位bytes作为加密密钥 跟flask session的secret key类似

session是一个dict like的对象

设定session

  1. from aiohttp import web
  2. import datetime
  3. from aiohttp_session import get_session
  4. async def login(request):
  5. engine = await aio_engine.init_engine()
  6. data = await request.json()
  7. print("data", data)
  8. if "name" not in data or "psw" not in data:
  9. return web.json_response({
  10. "status": False
  11. })
  12. name = data["name"]
  13. psw = data["psw"]
  14. verify = await keeper.verify(engine, name = name, psw = psw)
  15. if verify:
  16. session = await get_session(request)
  17. session["ooad"] = name
  18. session["login"] = psw
  19. session["time"] = str(datetime.datetime.now())
  20. return web.json_response({
  21. "status": True
  22. })
  23. return web.json_response({
  24. "status": False
  25. })

检查是否含有具体session字段值

  1. from aiohttp import web
  2. import datetime
  3. from aiohttp_session import get_session
  4. async def need_cookies_page(request):
  5. engine = await aio_engine.init_engine()
  6. session = await get_session(request)
  7. if "ooad" not in session or "login" not in session or "time" not in session:
  8. return web.json_response({
  9. "status": False
  10. })
  11. name = session["ooad"]
  12. psw = session["login"]
  13. r = await keeper.verify(engine, name = name, psw = psw)
  14. if r:
  15. return web.json_response({
  16. "status": True
  17. })
  18. return web.json_response({
  19. "status": False
  20. })
  21. ````
  22. setup app
  23. <div class="md-section-divider"></div>
  24. ```python
  25. setup(app, EncryptedCookieStorage(b'Thirty two length bytes key.'))

效果

login result
image_1cfrgldqfjrht9n1gva149ocj423.png-72.7kB
login cookies
image_1cfrgm0d8nov172b2mj10ta4g62g.png-46.1kB
cookies check
image_1cfrgn8mh1vf717qu1elcqdv8ur2t.png-43.3kB


使用redis存储session

这里有个问题 就是aiohttp本事内置一个asyncio event loop执行所有跟app相关的协程了 但是当我们使用redis作为仓库进行存储session的时候需要使用到aioredis进行支持 但是这个也是异步io连接模块 因此我们初始化redis pool的时候也需要一个event loop进行运行这个初始化的协程 一旦这个event loop跟web.run_app混在一起就会报错 event loop is already run

正确的做法是分开 并且在执行redis pool连接的event loop run_until_complete处获取返回值 得到需要的storage

  1. from aiohttp_session import setup, redis_storage
  2. import aioredis
  3. import asyncio
  4. async def get_storage():
  5. redis = await aioredis.create_pool(("localhost", 6379))
  6. return redis_storage.RedisStorage(redis)
  7. def setup_session_support(app):
  8. storage = asyncio.get_event_loop().run_until_complete(get_storage())
  9. setup(app, storage)
  10. return app
  1. app = session_redis.setup_session_support(app)

效果
可以看到生成的cookies值确实存在了redis中
postman中获取的cookies
image_1cfs5ia7pm0mke1hcn13edld9m.png-18.6kB
redis中也存有一样的cookies
image_1cfs5h8s6st01coa4491gh0bic9.png-20kB

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注