玩蛇记-给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开始的时候过程如下图:

image

当一个request结束之后,过程如下图:

image

 

理清楚处理的逻辑我们就能开始编码了,首先我们需要用一个对象来存储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有所帮组

posted on 2010-05-28 00:17  亚历山大同志  阅读(13042)  评论(8编辑  收藏  举报

导航