zoukankan      html  css  js  c++  java
  • 自定义Tornado的session组件

    session和cookie的关系

    cookie:保存在客户端浏览器上的键值对
    	session_id = "eyJ1c2VyX2luZm8iOiJ"
    
    session:保存在服务器上的键值对
    	{
    		"eyJ1c2VyX2luZm8iOiJ":{'is_login':True, 'user':'standby',...},
    		"iJhbGV4In0.DYUE4A.A":{'is_login':True, 'user':'alex',...},
    		...
    	}
    
    - 用户第一次打开浏览器请求我的网站页面
    	- 在服务器端生成一个随机字符串,作为value发给客户端浏览器。
    	- 这个随机字符串在服务器的session中作为key,value={},保存起来。
    

    知识准备

    1. 通过给定字符串,如何实例化一个对象出来?

    import importlib
    path = "session_code.RedisSession"
    md,cls = path.rsplit('.',maxsplit=1)
    m = importlib.import_module(md)
    cls = getattr(m,cls)
    print(cls.__name__)
    

     或者

    import importlib
    path = "scrapy.middleware.MiddlewareManager"
    tmp_li = path.split('.')
    cls_name = tmp_li.pop()
    prefix = '.'.join(tmp_li)
    m = importlib.import_module(prefix)
    cls = getattr(m,cls_name)
    print(cls.__name__)
    

    rest_framework/setting.py

    def import_from_string(val, setting_name):
        """
        Attempt to import a class from a string representation.
        """
        try:
            # Nod to tastypie's use of importlib.
            module_path, class_name = val.rsplit('.', 1)
            module = import_module(module_path)
            return getattr(module, class_name)
        except (ImportError, AttributeError) as e:
            msg = "Could not import '%s' for API setting '%s'. %s: %s." % (val, setting_name, e.__class__.__name__, e)
            raise ImportError(msg)

    from django.utils.module_loading import import_string

    def import_string(dotted_path):
        """
        Import a dotted module path and return the attribute/class designated by the
        last name in the path. Raise ImportError if the import failed.
        """
        try:
            module_path, class_name = dotted_path.rsplit('.', 1)
        except ValueError:
            msg = "%s doesn't look like a module path" % dotted_path
            six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
    
        module = import_module(module_path)
    
        try:
            return getattr(module, class_name)
        except AttributeError:
            msg = 'Module "%s" does not define a "%s" attribute/class' % (
                module_path, class_name)
            six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])

    2. 面向对象里的 __setitem__ __getitem__ 

    class Foo(object):
        def __getitem__(self, item):
            return "123"
        def __setitem__(self, key, value):
            self.__dict__[key] = value
        def __delitem__(self, key):
            print('----')
            self.__dict__.pop(key)
    
    obj = Foo()
    print(obj['k1'])    # __getitem__
    
    obj['k1'] = 666     # __setitem__
    
    del obj['k1']       # __delitem__
    
    
    
    Django 里面操作session:
        request.session['xxx'] = xxxxx
    

    3. 程序结合配置文件以及工厂模式

    class MemSession(object):
        def __getitem__(self, item):
            return "123"
    
        def __setitem__(self, key, value):
            self.__dict__[key] = value
    
        def __delitem__(self, key):
            print('----')
            self.__dict__.pop(key)
    
    class RedisSession(object):
        def __getitem__(self, item):
            return "123"
    
        def __setitem__(self, key, value):
            self.__dict__[key] = value
    
        def __delitem__(self, key):
            print('----')
            self.__dict__.pop(key)
    
    
    class SessionFactory(object):
        """
            工厂模式
            settings.py :  SESSION_ENGINE = "session_code.RedisSession"
        """
    
        @staticmethod
        def get_session(self):
            import settings
            engine = settings.SESSION_ENGINE
            import importlib
            module_path,cls_name = engine.split('.',maxsplit=1)
            md = importlib.import_module(module_path)
            cls = getattr(md,cls_name)
            return cls
    

      

    Tornado基于内存和redis的session组件实现示例

    app.py

    from tornado import ioloop
    from tornado.web import RequestHandler,Application
    from session_code import SessionFactory
    
    settings = {
        'template_path':'templates',
    }
    
    class SessionHandler(object):
        def initialize(self):
            cls = SessionFactory.get_session()
            self.session = cls(self)
    
    class IndexHandler(SessionHandler,RequestHandler):
    
        def get(self):
            user = self.session['user']
            if user:
                self.write("首页欢迎你")
            else:
                self.redirect('/login')
    
    class LoginHandler(SessionHandler,RequestHandler):
    
        def get(self):
            self.render('login.html',msg="")
        def post(self, *args, **kwargs):
            name = self.get_argument('name')
            pwd = self.get_argument('pwd')
            if 'alex'==name and '123' == pwd:
                self.session['user'] = name
                self.redirect('/index')
            else:
                self.render('login.html',msg="用户名或密码错误")
    
    application = Application([
        (r"/index", IndexHandler,{},'alias_name1'),
        (r"/login", LoginHandler,{},'alias_name2'),
    ],**settings)
    
    if __name__ == "__main__":
        application.listen(8090)
        ioloop.IOLoop.instance().start()
    

    session_code.py

    import json
    import time
    import hashlib
    import settings
    
    def gen_random_str():
        md5 = hashlib.md5()
        md5.update(str(time.time()).encode('utf-8'))
        return md5.hexdigest()
    
    
    class MemSession(object):
        ''' 静态字段在类里只保存一份(不管实例化多少次,用的都是同一份) '''
        container = {}
    
        def __init__(self,handler):
            self.handler = handler
            self.session_id = settings.SESSION_ID
            self.expires = settings.EXPIRES
            self.initial()
    
        def initial(self):
            client_random_str = self.handler.get_cookie(self.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] = {} # 给服务端设置session
            expires = time.time() + self.expires
            self.handler.set_cookie(self.session_id,self.random_str,expires=expires) # 给客户端设置cookie
    
        def __getitem__(self, item):
            return self.container[self.random_str].get(item)
    
        def __setitem__(self, key, value):
            self.container[self.random_str][key] = value
            print(self.container)
    
        def __delitem__(self, key):
            if key in self.container[self.random_str]:
                del self.container[self.random_str][key]
    
    class RedisSession(object):
    
        def __init__(self,handler):
            self.handler = handler
            self.session_id = settings.SESSION_ID
            self.expires = settings.EXPIRES
            self.initial()
    
        def get_redis_conn(self):
            import redis
            conn = redis.Redis(host='8.8.8.8', port=6379)
            return conn
    
        def initial(self):
            self.redis_conn = self.get_redis_conn()
            client_random_str = self.handler.get_cookie(self.session_id)
            if client_random_str and self.redis_conn.exists(client_random_str):
                self.random_str = client_random_str
            else:
                self.random_str = gen_random_str()
    
            expires = time.time() + self.expires
            self.handler.set_cookie(self.session_id,self.random_str,expires=expires) # 给客户端设置cookie
            self.redis_conn.expire(self.random_str,self.expires) # 给redis设置超时时间
    
        def __getitem__(self, item):
            # redis 返回的是byte类型,所以需要decode
            data_str = self.redis_conn.hget(self.random_str,item)
            if data_str:
                return json.loads(data_str.decode('utf-8'))
    
        def __setitem__(self, key, value):
            # val = {'type':type(value).__name__,'value':value}
            self.redis_conn.hset(self.random_str,key,json.dumps(value))
    
        def __delitem__(self, key):
            self.redis_conn.hdel(self.random_str,key)
    
    class SessionFactory(object):
        """
            工厂模式
        """
        @staticmethod
        def get_session():
            import settings
            engine = settings.SESSION_ENGINE
            import importlib
            module_path,cls_name = engine.split('.',maxsplit=1)
            md = importlib.import_module(module_path)
            cls = getattr(md,cls_name)
            return cls
    

    settings.py

    SESSION_ENGINE = "session_code.RedisSession"
    SESSION_ID = "__session_id__"
    EXPIRES = 300
    

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <h1 class="c1">Login</h1>
    <form action="" method="post">
        <input type="text" name="name">
        <input type="text" name="pwd">
        <input type="submit" value="提交"> {{ msg }}
    </form>
    
    
    </body>
    </html>
    

      

    作者:Standby一生热爱名山大川、草原沙漠,还有妹子
    出处:http://www.cnblogs.com/standby/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    洛谷1113 杂务
    MySQL中的各种引擎
    剑指offer第3题:从尾到头打印链表
    向一个GitHub repository添加协作者
    String、StringBuffer与StringBuilder之间区别
    java与C语言在字符串结束符上的区别
    git 查看远程分支、本地分支、创建分支、把分支推到远程repository、删除本地分支
    Git问题Everything up-to-date解决
    Mybatis 数据库物理分页插件 PageHelper
    时间序列分析发展史
  • 原文地址:https://www.cnblogs.com/standby/p/8544295.html
Copyright © 2011-2022 走看看