自定义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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://www.cnblogs.com/standby/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。