• 关于Cookie和Session


    简单的说

    • 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
  • 相关阅读:
    第三章预习
    预习非数值数据的编码方式
    预习原码补码
    第三章——运算方法和运算部件预习
    预习非数值数据的编码方式
    预习原码补码(习题+预习)
    预习非数值数据的编码方式
    预习原码补码
    10.21
    10.7作业
  • 原文地址:https://www.cnblogs.com/mayite/p/9650753.html
Copyright © 2020-2023  润新知