玩蛇记-给tornado加上session支持
WARNING!
阅读本文需要具有使用python编程的能力以及Web编程的经验,起码应该知道python是什么,Session是什么。初学者慎入,某些描述语焉不详,小心误入歧途,欢迎高手踊跃拍砖。本文代码仅仅作为示例使用,用于说明在tornado中实现session的过程以及方法,未经过任何编译或者运行,请勿直接copy到项目中使用,本人不对此行为造成的后果负任何责任。(此文实现内容源于商业项目,恕未能直接提供源码)
----------------------------------------------------------
tornado没有提供默认的会话,而很多敏感信息又没法用cookie存,tornado提供的secure_cookie只是解决了防止cookie篡改而没法阻止数据被解密为明文,所以我就给tornado写了一个session的包来解决这个问题。嗯,我们来看看是如何从底层一砖一瓦的来实现Session的功能。
根据项目的需要我采用Memcached作为Session的backend,当然你愿意用Mysql或者是其他什么能存储数据的东西都行,比如文本文件或者mongodb,选择很多,所以我们将Session需要持久化的操作独立出来成为一个可以替换的backend模块,我们可以根据配置使用不同的backend,由于python得ducktyping特性,要实现起来相当的简单,我们只需要提供包含如下三个方法签名的类就行了
class backend():
def getitem(self,key):
def setitem(self,key,value,timeout)
def deleteitem(self,key)
对于Memcached我们需要在backend类中保持一个Memcached的连接,大体上的实现如下:
from memcache import Client
class backend():
def __init__(self):
self.conn=Client([‘127.0.0.1:11211’])
def getitem(self,key):
return self.conn.get(key)
def setitem(self,key,value,timeout):
self.conn.set(key,value,timeout)
def deleteitem(self,key):
self.conn.delete(key)
当然实际应用中我们不会写得这么简陋了,连接的服务器信息都是从配置文件里取得的。这样我们就有了一个Session的backend了,如果你想用Mysql作为backend,那么可以按照这个原理来改写一个backend类
有了Session数据的持久化backend后我们就可以开始编写Session类本身了,首先我们来回顾一下Session的工作原理。基本上大部分的Session都是通过Cookie配置服务端持久化来实现Session的,cookie保持用户创建会话的SessionID,然后在每次访问的时候通过SessionID到持久化服务中去取这个Session的数据。当一个request开始的时候过程如下图:
当一个request结束之后,过程如下图:
理清楚处理的逻辑我们就能开始编码了,首先我们需要用一个对象来存储Session的数据,一般来说Session都按照Key-Value的形式存储,所以我们可以用一个Dict来作为Session的存储对象,但是我们还需要一个Session ID,所以我们继承一个dict
class SessionData(dict):
def __inti__(self,id=none):
self.id=id
def __getitem__(self,key):
if self.has_key(key):
return self[key]
return None
def __setitem__(self,key,value):
self[key]=value
然后我们实现一个decorator来在一个request前和request后来恢复和保存Session
def Session(request):
def Process(handler,*args):
#请求前恢复Session对象的过程
item=handler.application.backend.getitem(handler.get_secure_cookie(‘session_id’,’’))
data=None
if item:
data=new SessionData(item.id)
data.update(item)
else:
data=new SessionData()
handler.set_secure_cookie(“session_id”,””)
handler.setattr(“session”,data)
request(handler,*args)#执行原本请求的方法
#请求完成后保存session的过程
if data.id:
handler.application.backend.setitem(data.id,data)
else:
if len(data.keys()):
data.id=str(uuid1.uuid1())
handler.set_secure_cookie(“session_id”,data.id)
handler.application.backend.setitem(data.id,data)
这个方法有点长,不过逻辑就是这么样子的,实现了这个decreator之后我们只需要在需要使用Session的请求前加上@Session,就能够通过self.session来使用session咯。
接下来想在项目里使用还有一些具体的问题要解决,但是基本原理和实现方式在本文的内容就到此为止了,接下来的工作应该难不倒能看懂此文的同学,如果看着如同天书,那么多半是对python或者tornado没有什么了解,请自行弥补基础知识。希望此文能够对正在实践python和tornado的TX有所帮组