为tornado ,采用mongodb 加上session功能(web.py等 框架也可以参考本文)

来源:互联网 发布:php 命令行参数 编辑:程序博客网 时间:2024/05/29 03:23
1, session的原理 
http是无状态协议, 理论上说,无法管理和跟踪客户端信息,1994年网景公司,在http的基础上增加了cookie,用于在客户端保存客户信息,后来cookie也称了http的标准。 
session是建立在cookie的基础之上, 实现方法为, 在客户端使用cookie保存session_id, http serve 从cookie得到session_id后,通过session_id得到客户的对应信息。 (至于怎么得到, 以及session怎么保存,取决怎么实现) 

2, tornado http server 为一个基于epoll的高性能http 服务, 有facebook 捐献, 被广泛的用于facebook(facebook的http服务,都由tornado提供) 

3,tonado上实现session功能 (session 采用mongodb保存) 

思路如下, 
1, 从cookie中获取session_id, 如果有的话,就从mongodb中load对应的sessin 
2, 如果没有, 创建空session 
3, 如果当前没有session, 保存时,需要通过cookie设置 session_id 

模块 
1, SessionManager sessin管理,负责保存session, load session ,生成唯一的session_id等功能 
2, BaseSession session的基础实现 

本案例sessionManager 采用mongoDB为后端 

Python代码  收藏代码
  1. ## --------------------------------------------  
  2.   
  3. # session manager  
  4.   
  5. class SessionManagerBase(object):  
  6.     """session manager的基类"""  
  7.     def generate_session_id(self, salt):  
  8.         """生成唯一的session_id"""  
  9.         rand = os.urandom(16)  
  10.         now = time.time()  
  11.         return sha1("%s%s%s" %(rand, now, salt)).hexdigest()  
  12.   
  13.     def create_new(self, session_id):  
  14.         """创建空session,当session不存在时"""  
  15.         pass  
  16.   
  17.     def save_session(self, session):  
  18.         """保存session"""  
  19.         pass  
  20.   
  21.     def load_session(self, session_id = None):  
  22.         """根据session_id load session"""  
  23.         pass  
  24.   
  25.   
  26. ## --------------------------------------------  
  27.   
  28. class MongoSessionManager(SessionManagerBase):  
  29.     def __init__(self, db, collection_name='sessions', **kw):  
  30.         """session 采用mongodb为后端保存, 默认是存在 sessions 集合中"""  
  31.         self._collection = db[collection_name]  
  32.   
  33.     def create_new(self, session_id):  
  34.         return BaseSession(session_id, self, {})  
  35.   
  36.     def save_session(self, session):  
  37.         """保存session 到mongodb"""  
  38.         self._collection.save({'_id' : session.get_session_id(), 'data' : session})  
  39.   
  40.     def load_session(self, session_id = None):  
  41.         data = {} # 默认为空session  
  42.         if session_id:  
  43.             # 有session ,就调入  
  44.             session_data = self._collection.find_one({'_id' : session_id})  
  45.             if session_data:  
  46.                 # 防止错误数据  
  47.                 data = session_data['data']  
  48.   
  49.         return BaseSession(session_id, self, data)  
  50.   
  51. ## --------------------------------------------  
  52. # session  
  53.   
  54. class BaseSession(dict):  
  55.     def __init__(self, session_id = '', mgr = None, data = {}):  
  56.         self.__session_id = session_id  
  57.         self.__mgr = mgr  
  58.         self.update(data)  
  59.         self.__change = False # 小小的优化, 如果session没有改变, 就不用保存了  
  60.   
  61.     def get_session_id(self):  
  62.         return self.__session_id  
  63.     
  64.     def save(self):  
  65.         if self.__change:  
  66.             self.__mgr.save_session(self)  
  67.             self.__change = False  
  68.   
  69.     # ------------------------------------------  
  70.     # 使用session[key] 当key不存在时返回None, 防止出现异常  
  71.     def __missing__(self, key):  
  72.         return None  
  73.   
  74.     def __delitem__(self, key):  
  75.         if key in self:  
  76.             del self[key]  
  77.             self.__change = True  
  78.   
  79.     def __setitem__(self, key, val):  
  80.         self.__change = True  
  81.         super(BaseSession, self).__setitem__(key, val)  
  82.           


以上为sessionmanager 和 basesession的代码, 看看注释,就能明白了。 

3 使用 
有2中方法, 1, 继承tornado 的 RequestHandler, 在子类中实现get_session 这个方法 
实现方便,但这个方式需要引入新的类,而且session 代码需要和特定服务器耦合,如果需要请自己实现。 

在此要讨论的是另一种思路,采用函数装饰来实现 

session_settings 保存session的配置, 整个session的配置会放在RequestHandler的settings中 

Python代码  收藏代码
  1. def session(func):  
  2.     @functools.wraps(func)  
  3.     def warpper(self, *args, **kwargs):  
  4.         self.require_setting('session_settings''session')  
  5.         # 获取session配置信息  
  6.         session_settings = self.settings['session_settings']  
  7.         # 取得session manager  
  8.         mgr = session_settings['mgr']  
  9.   
  10.         #通过cookie 得到session_id  
  11.         cookie_name = session_settings['cookie_name']  
  12.         session_id = self.get_secure_cookie(cookie_name)  
  13.   
  14.         # 得到session ,并保存在request.session中  
  15.         if session_id:  
  16.             #如果有session 直接调出  
  17.             setattr(self'session', mgr.load_session(session_id))  
  18.         else:  
  19.             # 当前没有session ,需要保存session_id到cookie中, 并返回新建的空session  
  20.             secret_key = session_settings['secret_key']  
  21.             session_id = mgr.generate_session_id(secret_key)  
  22.             self.set_secure_cookie(cookie_name, session_id)  
  23.             setattr(self'session', mgr.create_new(session_id))  
  24.   
  25.         return_val = func(self, *args, **kwargs)  
  26.   
  27.         # 在被装饰的函数执行后, 保存session  
  28.         self.session.save()  
  29.   
  30.         return return_val  
  31.       
  32.     return warpper  


4, 使用 

Python代码  收藏代码
  1. # -*- coding: utf-8 -*-  
  2.   
  3. # ---------------------------  
  4. #DB  
  5.   
  6. from xanadu import MongoSessionManager  
  7. from xanadu.nosql import *  
  8.   
  9. db = open_db('10.45.12.197')  
  10.   
  11. test_db = db('test')  
  12. session_mgr = MongoSessionManager(test_db)  
  13.   
  14.   
  15. # ---------------------------  
  16. # settings  
  17.   
  18. cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo="  
  19.   
  20. session_settings = {  
  21.     'mgr' : session_mgr,  
  22.     'cookie_name''session_id',  
  23.     'cookie_domain'None,  
  24.     'cookie_expires'86400#24 * 60 * 60, # 24 hours in seconds  
  25.     'ignore_expiry'True,  
  26.     'ignore_change_ip'True,  
  27.     'secret_key': cookie_secret,  
  28.     'expired_message''Session expired',  
  29.     'httponly'True  
  30. }  
  31.   
  32. dbs = {  
  33.     'default' : test_db,  
  34. }  
  35.   
  36. db_sessions = {  
  37.     'default' = open_session(test_db)  
  38. }  
  39.   
  40. static_path = 'static'  
  41.   
  42. # ---------------------------  
  43.   
  44.   
  45. from xanadu import test  
  46. from xanadu import RequestHandlerEx  
  47. from xanadu.ctl import *  
  48.   
  49. import tornado  
  50.   
  51. class HelloHandler(RequestHandlerEx):  
  52.     def get(self):  
  53.         self.write('Hello')  
  54.   
  55. application = tornado.web.Application(  
  56.     [  
  57.         (r"/login", LoginHandler),  
  58.         (r"/test_session", test.session.TestSessionHandler2),  
  59.         (r"/hello", HelloHandler),  
  60.     ],  
  61.     **locals()  
  62. )  
0 0
原创粉丝点击