简单的说
Cookie 是保存在浏览器的键值对
Session 是保存在服务端的键值对
Session 是依赖于 Cookie 的
在 Django 框架中, 我们可以直接操作 cookie 和 session, 但是 tornado 只支持 cookie, 那如果要使用 session 怎么办呢? 自己定义 session
基于内存实现 SESSION
我们知道, 在 tornado 中, 所有的请求都是由 RequestHandler 对象来处理 (以下简称 handler 对象). 在 RequestHandler 源码中, 预留了一个钩子方法 initialize, 该方法会在实例化 Handler 对象时执行. 因此, 如果我们继承 RequestHandler 类并重写 initialize, 就可以完成一些自定义操作.
- import os
- import tornado.ioloop
- import tornado.web
- from tornado.web import RequestHandler
- import hashlib
- import time
- # 生成一个随机的字符串
- def gen_random_str():
- md5 = hashlib.md5()
- md5.update(str(time.time()).encode('utf-8'))
- return md5.hexdigest()
- class CacheSession(object):
- container = {}
- def __init__(self,handler):
- self.handler = handler
- client_random_str = self.handler.get_cookie("_session_id_")
- if client_random_str and client_random_str in self.container:
- self.random_str = client_random_str
- else:
- self.random_str = gen_random_str()
- self.container[self.random_str] = {}
- expires = time.time() + 300
- self.handler.set_cookie("_session_id_", self.random_str, expires=expires)
- def __setitem__(self, key, value):
- self.container[self.random_str][key] = value
- def __getitem__(self, item):
- return self.container[self.random_str].get(item)
- class SessionHandler(RequestHandler):
- def initialize(self):
- # self 指代的是当前的对象
- self.session = CacheSession(self)
- class LoginHandler(SessionHandler,RequestHandler):
- def get(self, *args, **kwargs):
- self.render('login.html')
- def post(self, *args, **kwargs):
- username = self.get_argument('username')
- password = self.get_argument('password')
- if username == 'admin' and password == '123':
- self.session['username'] = username
- self.redirect('/main')
- else:
- self.redirect('/login')
- class MainHandler(SessionHandler,RequestHandler):
- def get(self, *args, **kwargs):
- username = self.session['username']
- if username:
- self.write('this is main page')
- else:
- self.redirect('/login')
- def post(self, *args, **kwargs):
- pass
- settings = {
- "static_path" : os.path.join(os.path.dirname(__file__),'static'),
- "static_url_prefix":"static",
- "template_path":'views',
- "xsrf_cookies": True,
- }
- def make_app():
- return tornado.web.Application([
- (r"/login", LoginHandler),
- (r"/main", MainHandler),
- ], **settings)
- if __name__ == "__main__":
- app = make_app()
- app.listen(8888)
- tornado.ioloop.IOLoop.current().start()
代码解释
定义一个 Session 类, 其实例化时接收 handler 对象
在 Session 类中定义一个静态字段 (大字典), 用来存储 session_id 和对应的用户信息; 所有的 session 对象都可以访问这个大字典.
在 Session 的构造方法中, 获取和设置 cookie:
调用 handler 对象 get_cookie() 方法获取 session_id, 如果没有, 则生成一段随机字符串 random_str 作为 session_id
将 session_id 写入大字典
调用 handler 对象的 set_cookie() 方法, 通知浏览器设置
cookie:set-cookie: {session_id: random_str}
在 Session 类中, 定义__getitem__, __setitem__, __delitem__方法来实现通过字典的方式操作 session 对象
在 initialize 方法中为 handler 对象增加 session 属性, 其值是 Session 对象: self.session=Session(self); 在每个路由对应的视图中都重写 initialize 方法太麻烦了, 利用面向对象的多继承, 将这一步单独写在一个类 SessionHandler, 所以视图类先继承这个类即可
每次请求进来, 都会执行 SessionHandler 中的 initialize 方法, 并实例化 Session 对象, 从而获取 session_id
操作 session:
通过
self.session[key] = value
, 即可调用 session 对象的__setitem__方法来写 session;
通过 self.session[key] 即可调用 session 对象的__getitem__方法来获取 session
通过
del self.session[key]
即可调用 session 对象的__delitem__方法来删除 session
基于 Redis 实现 Session
- import os
- import tornado.ioloop
- import tornado.web
- from tornado.web import RequestHandler
- import hashlib
- import time
- def gen_random_str():
- md5 = hashlib.md5()
- md5.update(str(time.time()).encode('utf-8'))
- return md5.hexdigest()
- class RedisSession(object):
- @property
- def conn(self):
- import redis
- conn = redis.Redis(host='192.168.11.96', port=6379)
- return conn
- def __init__(self,handler):
- self.handler = handler
- client_random_str = self.handler.get_cookie("_session_id_")
- if client_random_str and self.conn.exists(client_random_str):
- self.random_str = client_random_str
- else:
- self.random_str = gen_random_str()
- expires = time.time() + 300
- self.handler.set_cookie("_session_id_", self.random_str, expires=expires)
- self.conn.expire(self.random_str, 300)
- def __setitem__(self, key, value):
- self.conn.hset(self.random_str, key, value)
- def __getitem__(self, item):
- return self.conn.hget(self.random_str, item)
- class SessionHandler(RequestHandler):
- def initialize(self):
- self.session = RedisSession(self)
工厂模式实现 Session
session_code.py
- class SessionFactory(object):
- @staticmethod
- def get_session():
- import settings
- import importlib
- engine = settings.SESSION_ENGINE
- module_path,cls_name = engine.rsplit('.',maxsplit=1)
- md = importlib.import_module(module_path)
- cls = getattr(md,cls_name)
- return cls
app.py
- from session_code import SessionFactory
- cls = SessionFactory.get_session()
- print(cls)
setting.py
- SESSION_ENGINE = "session_code.RedisSession"
- # SESSION_ENGINE = "session_code.CacheSession"
- SESSION_ID = "__session__id__"
- EXPIRERS = 300
来源: https://www.cnblogs.com/mayite/p/9650753.html