浏览 7776 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (4) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-08-14
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为后端 ## -------------------------------------------- # session manager class SessionManagerBase(object): """session manager的基类""" def generate_session_id(self, salt): """生成唯一的session_id""" rand = os.urandom(16) now = time.time() return sha1("%s%s%s" %(rand, now, salt)).hexdigest() def create_new(self, session_id): """创建空session,当session不存在时""" pass def save_session(self, session): """保存session""" pass def load_session(self, session_id = None): """根据session_id load session""" pass ## -------------------------------------------- class MongoSessionManager(SessionManagerBase): def __init__(self, db, collection_name='sessions', **kw): """session 采用mongodb为后端保存, 默认是存在 sessions 集合中""" self._collection = db[collection_name] def create_new(self, session_id): return BaseSession(session_id, self, {}) def save_session(self, session): """保存session 到mongodb""" self._collection.save({'_id' : session.get_session_id(), 'data' : session}) def load_session(self, session_id = None): data = {} # 默认为空session if session_id: # 有session ,就调入 session_data = self._collection.find_one({'_id' : session_id}) if session_data: # 防止错误数据 data = session_data['data'] return BaseSession(session_id, self, data) ## -------------------------------------------- # session class BaseSession(dict): def __init__(self, session_id = '', mgr = None, data = {}): self.__session_id = session_id self.__mgr = mgr self.update(data) self.__change = False # 小小的优化, 如果session没有改变, 就不用保存了 def get_session_id(self): return self.__session_id def save(self): if self.__change: self.__mgr.save_session(self) self.__change = False # ------------------------------------------ # 使用session[key] 当key不存在时返回None, 防止出现异常 def __missing__(self, key): return None def __delitem__(self, key): if key in self: del self[key] self.__change = True def __setitem__(self, key, val): self.__change = True super(BaseSession, self).__setitem__(key, val) 以上为sessionmanager 和 basesession的代码, 看看注释,就能明白了。 3 使用 有2中方法, 1, 继承tornado 的 RequestHandler, 在子类中实现get_session 这个方法 实现方便,但这个方式需要引入新的类,而且session 代码需要和特定服务器耦合,如果需要请自己实现。 在此要讨论的是另一种思路,采用函数装饰来实现 session_settings 保存session的配置, 整个session的配置会放在RequestHandler的settings中 def session(func): @functools.wraps(func) def warpper(self, *args, **kwargs): self.require_setting('session_settings', 'session') # 获取session配置信息 session_settings = self.settings['session_settings'] # 取得session manager mgr = session_settings['mgr'] #通过cookie 得到session_id cookie_name = session_settings['cookie_name'] session_id = self.get_secure_cookie(cookie_name) # 得到session ,并保存在request.session中 if session_id: #如果有session 直接调出 setattr(self, 'session', mgr.load_session(session_id)) else: # 当前没有session ,需要保存session_id到cookie中, 并返回新建的空session secret_key = session_settings['secret_key'] session_id = mgr.generate_session_id(secret_key) self.set_secure_cookie(cookie_name, session_id) setattr(self, 'session', mgr.create_new(session_id)) return_val = func(self, *args, **kwargs) # 在被装饰的函数执行后, 保存session self.session.save() return return_val return warpper 4, 使用 # -*- coding: utf-8 -*- # --------------------------- #DB from xanadu import MongoSessionManager from xanadu.nosql import * db = open_db('10.45.12.197') test_db = db('test') session_mgr = MongoSessionManager(test_db) # --------------------------- # settings cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=" session_settings = { 'mgr' : session_mgr, 'cookie_name': 'session_id', 'cookie_domain': None, 'cookie_expires': 86400, #24 * 60 * 60, # 24 hours in seconds 'ignore_expiry': True, 'ignore_change_ip': True, 'secret_key': cookie_secret, 'expired_message': 'Session expired', 'httponly': True } dbs = { 'default' : test_db, } db_sessions = { 'default' = open_session(test_db) } static_path = 'static' # --------------------------- from xanadu import test from xanadu import RequestHandlerEx from xanadu.ctl import * import tornado class HelloHandler(RequestHandlerEx): def get(self): self.write('Hello') application = tornado.web.Application( [ (r"/login", LoginHandler), (r"/test_session", test.session.TestSessionHandler2), (r"/hello", HelloHandler), ], **locals() ) 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-08-30
好文啊!以前做过mongo替换jetty的,tonado,mark了。
|
|
返回顶楼 | |