Skip to content
No description, website, or topics provided.
Python HTML
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
demo
tornadopy
.gitattributes
.gitignore
.travis.yml
README.md
requirements.txt
setup.py

README.md

#tornadopy Web Framework A simple app web framework based on tornado.

###version:1.0.0

tornadopy 是基于Tornado的web mvc框架。tornadopy 大量参考和借鉴了Django的设计模式,形成一套基于tornado的Django like应用层开发框架。tornado 建议使用4.0以上版本,注意:tornadopy不支持基于WSGI的应用。

##框架依赖

  • future
  • tornado>=3.2

##安装

  • pip: pip install tornadopy

##快速入门


  • ####目录结构示例:

      |- app
          +- myapp1
          |   |- urls.py
          |   |- handlers
          |       |- hello_china.py
          |       |- hello_usa.py
          |       |- ...
          |          
          +- myapp2
          |   |- ...
          |
          +- logs
          |
          +- middlewares
          |   |- ...
          |
          +- settings
          |   |- settings.py
          |   |- settings_online.py
          |
          +- httpmodules
          |   |- ...
          |
          +- templates
          |   |- ...
          |
          +- statics
          |   |- ...
          +- runserver.py
    
    • project_web :

      你可以参考project目录下的 `project_web` 项目示例,并运行:
      
      	python demo/runserver.py --address=0.0.0.0 --port=8000 --settings=settings.setting
      
      启动服务后,在浏览器中查看 `127.0.0.1:8000` ,你应该可以看到一个欢迎页面!
      
  • ####settings配置:

    在项目runserver.py中,你可以指定使用的预设值的默认配置文件,如配置文件在应用根目录app.settings下的setting.py:

      os.environ.setdefault('tornadopy_APP_SETTINGS', 'settings.setting')
    

    在程序启动时,首先会检查 --settings= 是否给定如--settings=settings.setting,框架将自动加载应用目录下settings模块中的setting.py配置文件,如果未规定,则使用以上预设值默认配置。在项目中使用配置:

      from tornadopy import settiings
      
      project_path = settings.PROJECT_PATH
    

    DEBUG: 控制应用是否处于debug状态,等同于 tornado的debug参数。
    XHEADERS: 控制是否开启httpserver的 xheaders。你不用再额外传递一个xheader参数。

  • ####webserver:

    最简单的server启动方式:

      from tornadopy.webserver import run
      run()
    

    这将启动一个默认的tornado进程,如果想控制更多细节,你可以:

      from tornadopy.webserver import Server
      from tornado.options import define
      define("your_arg", default='default', help='your command args', type=str)
      
      serv = Server()
      serv.parse_command() #你必须调用parse_command()来处理tornado options,否则无法加载配置
      serv.load_urls()
      serv.load_application(application=None) # 或根据你的需求自定义Application
      serv.server_start(sockets=None, **kwargs)
    

    很多情况下,我们希望对Application对象进行个性化的处理,通常,我们习惯于实现一个Application子类:

      from tornadopy.application import Application
    
      class MyApp(Application):
      	"""your custom code"""
    
      Server().load_application(MyApp)
      ...
    

    load_application 接收一个 tornadopy.applicatoin.Application 类实例或其子类

    如果要使用tornadopy的全部功能,你的自定义 application 不能直接继承于 tornado.web.Application

    Server对象的 server_startload_all 以及 tornadopy.run 支持自定义的 httpserver 参数

       Server().server_start(no_keep_alive=True,backlog=512)
    

    server.load_all :如果你希望控制一些细节,但是又希望更简单的启动服务 , load_all() 会是更好的选择。

      serv = Server()
      serv.load_all(application=MyApp,no_keep_alive=True,backlog=512)
      serv.start()
    

    server_start 不同的是,load_all,以及 tornadopy.run 会帮你自动 parse_command,处理tornado.options ,所以不需要手动调用它。其他方式你需要手动调用 parse_command

    parse_command: Server对象的 parse_command 方法的作用等同于 tornado 中的 parse_command_line 同时为你初始化 log日志配置,你必须放在 define 语句之后调用,否则定义的参数将不起作用。

    你可能注意到 start 方法,这个方法类似于ioloop.start ,同时在debug模式下打印一些基础启动信息。 server_start 还会帮你处理httpserver的加载。所以,当你使用server_start时,不需要在调用 start方法或 ioloop.start()

    当你使用 load_all 来载入 applicationhttpserver 时,使用 start 是更好的选择 。

  • ####app:

    如顶述目录结构,您可以在应用根目录下创建多个app模块,假如你建立了应用myapp1,应用目录中必须包含 urls.py。 同时,要加载你的应用,你需要在配置文件中 INSTALLED_APPS 元组中增加你的app配置,如你的应用根目录app下存在myapp1,myapp2,则需:

      INSTALLED_APPS = (
      	'myapp1',
      	'myapp2',				
      )
    

    系统启动后,将自动加载myapp1,myapp2中的urls.py下的路由配置。

  • ####urls:

    每一个app都必须包含一个urls.py的路由表文件。你可以像这样配置路由:

      from tornadopy import Url, route
    
      u = Url('myapp1.handlers',abc='abc')
      urls = route(
          u(name='Index', pattern=r'/?', handler='main_handler.Main'),
      	u(name='Login', pattern=r'/login/?', handler='main_handler.Login'),
      	u(name='User', pattern=r'/user/?', handler='main_handler.User'),
      )
    

    Url()接受参数 prefix 模块前缀,上述例子中最终的加载handler模块为: myapp1.handlers.main_handler.Main. Url()还可以接受若干全局预加载参数。其作用等同于tornado 路由的kwargs参数,此参数将会被解析到每个handler的_url_kwargs变量中,如上述abc='abc'。

    main_handler.Main:

      from tornadopy.handler import WebHandler
      class Main(WebHandler):
      	def get(self):
      		self.finish(self._url_kwargs['abc']) # print abc
    

    每一个url还可以接受一个kwargs参数,这个参数仅对当前路由有效,其作用等同于上述的_url_kwargs,同样会被解析到_url_kwargs字典中。如果遇到同名参数,路由的kwargs会覆盖Url()中定义的同名参数,但仅影响当前路由。

      u(name='User', pattern=r'/user/?', handler='main_handler.User',kwargs={'abc':'other'}),
    

    你也可以直接import对应的handler:

      from myapp1.handlers.main_handler import Main
      u = Url()
      urls = route(
          u(name='Index', pattern=r'/?', handler=Main),
      )
    

    路由分组: 当你有许多路由时,为了便于管理,你可以将路由分散到多个文件中:

      url_photo.py:
    
      url=Url('myapp1.handlers')
      URLS = route(
          url(r'photo/upload/?','photo.UploadHandler'),
          ...
      )
    
      url_blog.py:
    
      url=Url('myapp1.handlers')
      URLS = route(
          url(r'blog/list/\d*/?','blog.ListHandler'),
          ...,
          
      )
      urls.py:
    
      from tornadopy import route
      from myapp1.url_blog import URLS as blog_urls
    
      url = Url('myapp1.handlers')
      URLS = route(
      	include('/','myapp1.url_photo.URLS'),
      	include('/',blog_urls),
      	url(r'/user/me/?','user.MeHandler'),
      )
    
  • ####log: tornadopy支持使用原生tornado日志模块,或tornadopy基于logging扩展日志,tornadopy默认启用扩展日志代替tornado默认的log,除非--disable_log=False ,则启用tornado.log模块 。

      from tornadopy.logger import syslogger
      
      syslogger.error("this is a error.")
    

    日志配置中的默认日志HANDLER默认为 tornadopy.logger.ProcessLogTimedFileHandler ,此handler支持在多进程状态下安全的写入日志文件,如需日志文件名按照端口号区分,通过设置 --log_port_prefix=true , --logging_dir 如果设定, 配置文件中的 LOGGING_DIR 将被忽略。

    你可以自定义你的日志配置,或新增日志,你只需要在LOGGING配置中加入类似段落:

              {
      'name': 'tornado',
      'level': 'INFO',
      'log_to_stderr': False,
      'when': 'midnight',
      'interval': 1,
      'filename': 'tornado.log'
      },
    

    注:请保留默认的几个日志配置。

  • ####模板引擎:

    在配置文件 TEMPLATE_CONFIG 中配置模板。 其中,template_engine 决定使用什么模板加载器(Loader) ,默认为 None,使用自带的模板引擎。 可选择使用 mako 或 jinja2 ,需要安装依赖库 mako或jinja2

      TEMPLATE_CONFIG = {
          'template_engine': 'tornadopy.template.mako_loader.MakoTemplateLoader' #使用mako模板
          'filesystem_checks': True,  # 通用选项
          'cache_directory': '../_tmpl_cache',  #通用选项,模版编译临时文件目录
          'collection_size': 50,  #mako选项,暂存入内存的模版项,可以提高性能,详情见mako文档
          'cache_size': 0,  #jinja选项,类似于mako的collection_size,设定为-1为不清理缓存,0则每次都会重编译模板
          'format_exceptions': False,  #mako选项,格式化异常输出
          'autoescape': False  #jinja2选项,默认转义设定
      	# 支持mako或jinja其他配置参数,详见相关文档。
      
      }
    
  • ####handler:

    如果需要使用tornadopy提供的功能,业务handler需要继承自 tornadopy.handler.WebHandlertornadopy.handler.ApiHandler .

    WebHandler提供了兼容mako,jinja2模板引擎加载,中间件hook的功能。并额外提供两个方法 on_preparecomplete_finish , 这两个方法分别在 prepareon_finish 方法执行结束后调用。

    同时,tornadopy提供了一个 FlashMessageMixIn ,可以配合handler实现消息闪现的功能,其作用类似flask中的flash。你的handler需要继承 FlashMessageMixIn

      class MyHandler(FlashMessageMixIn,WebHandler):
      	
      	def get(self):
      		self.flash("Welcome back, %s" % username, 'success')
    
      base.html
      ------------
    
      {% set messages = handler.get_flashed_messages() %}
      {% if messages %}
      <div id="flashed">
      	{% for category, msg in messages %}
      	<span class="flash-{{ category }}">{{ msg }}</span>
      	{% end %}
      </div>
      {% end %}
    
  • ####中间件:

    tornadopy实现了简单的中间件功能,其行为和功能类似于 Django 的中间件。在这里引用一张Django中间件的流程图:

    Django中间件流程

    我们可以参考这张图来理解tornadopy的中间件设计。tornadopy中间件遵循了类似于Django中间件的设计,但因为框架本身的差异性,tornadopy中间件 采用对RequestHandler执行流程中插入hook的方式,中间件默认没有返回值,你可以在需要的请求阶段对请求对象(request或handler)进行处理。

    *注:要使用中间件功能,你的handler必须继承自 tornadopy.handler.WebHandlertornadopy.handler.ApiHandler

    自定义中间件:

      class MyMiddleware(object):
          def process_init(self, application):
              """
              :param application: 应用程序对象,此方法在tornado启动时执行一次
              """
          def process_call(self, request, clear):
              """
              在请求request对象创建时,参数为请求对象,此时还未匹配路由handler
              :param request: 请求对象
              """
          def process_request(self, handler, clear):
              """
              匹配路由后,执行处理handler时调用
              :param handler: handler对象
              支持异步
              """
          def process_render(self, handler, clear, template_name, **kwargs):
              """
              此方法在调用render/render_string时发生
              :param handler: handler对象
              :param template_name: 模板名称
              :param kwargs: 模板参数
              """
          def process_response(self, handler, clear, chunk):
              """
              请求结束后响应时调用,此方法在render之后,finish之前执行,可以对chunk做最后的封装和处理
              :param handler: handler对象
              :param chunk : 响应内容,chunk为携带响内容的list,你不可以直接对chunk赋值,
      			可以通过chunk[index]来改写响应内容,或再次执行handler.write()
              """
          def process_endcall(self, handler, clear):
              """
              请求结束后调用,此时已完成响应并呈现用户,一般用来处理收尾操作,清理缓存对象,断开连接等
              :param handler: handler对象
              """
    
      	def process_exception(self,handler, clear, typ, value, tb):
              """
              请求过程引发异常时调用,你可以通过这个方法捕获在请求过程中的未捕获异常
      		如果没有中间件实现此方法,则调用tornado RequestHandler.log_exception方法。
              :param handler: handler对象
      		:param typ: 等同RequestHandler.log_exception的参数,异常类型值和异常堆栈信息
      		:param value:异常值信息
      		:param tb:异常堆栈
              """
    

    编写中间件需实现其中任何一个方法即可,中间件的执行流程中在请求阶段,call , request 按照中间件的声明顺序执行, 在响应过程中,exceptionresponseendcallrender 则是按声明顺序倒序执行) , 在tornado 4.0 中,process_request 支持异步调用。

    在中间件中返回任意真值,如 return 1,则停止当前请求的其余中间件相同方法的执行,进入下一个中间件流程。特别是当finish请求后,需return 1,例如:

      def process_request(self, handler, clear):
      	if not handler.user:
      		handler.finish('auth failure.')
      		return 1 
    

    调用finish后必须返回真值,return 1,这样会跳过剩余中间件的process_request方法,直接进入finish阶段 ,否则将继续执行 其余中间件process_request方法,以及get/post方法。

    clear: 如果希望当前请求剩余的所有中间件流程完全终止,则在方法头部调用此方法,以清空中间件的执行队列 与return 1不同,clear() 会导致其余的中间件全部方法在该请求中失效,而return 1只会导致所有中间件的当前流程方法失效。

    默认提供的中间件:

    • tornadopy.middleware.accesslog.AccessLogMiddleware :定制处理日志打印
    • tornadopy.middleware.dbalchemy.DBAlchemyMiddleware:使用SqlAlchemy需要引入该中间件
    • tornadopy.middleware.session.SessionMiddleware:提供session功能
    • tornadopy.middleware.session.SignalMiddleware:事件信号通知中间件,对django的signal封装

    中间件配置: MIDDLEWARE_CLASSES :实现中间件需要在配置文件中加入。其顺序决定中间件请求处理的顺序。 例如:

      MIDDLEWARE_CLASSES = (
      	# access_log中间件放在最上面,因为在响应阶段,最上边的中间件处理方法process_endcall会在最后执行。
          'tornadopy.middleware.accesslog.AccessLogMiddleware',
          'tornadopy.middleware.session.SessionMiddleware',
          'tornadopy.httpmodule.httpmodule.HttpModuleMiddleware',
      )
    
  • ####HTTP处理器:

    中间件提供了对请求处理流程的干预能力,使得我们可以控制请求过程中的各个方面。但是我们无法从容的对特定请求的特定过程进行干预。HTTP处理器提供了路由级别的请求处理能力。HTTP处理器分为两种: 全局处理器路由处理器

    你需要在中间件中加入 tornadopy.httpmodule.httpmodule.HttpModuleMiddleware 启用路由处理功能。

    自定义HTTP处理器模块需要继承自 tornadopy.httpmodule.BaseHttpModule ,并实现 begin_requestbegin_render , begin_response , complete_response 中任意一个方法即可,方法行为和功能类似中间件,同样, begin_request 方法在tornado4.0以上版本支持异步调用。

    HTTP处理器配置:

    • 全局处理器:通用路由处理器会处理所有请求的对应过程。行为等同于中间件,但是不同的是,在响应阶段,处理方法不同于中间件是倒序执行,而是顺序执行,同时需要注意的是,全局处理器总是优先于路由处理器之前执行。

        COMMON_MODULES = ( 
        	'httpmodule.auth.AuthModule',
        	'httpmodule.ipauth.ipblack',
        )
      
    • 路由处理器:根据配置在具体的路由请求中使用,格式为 '正则path或路由name':['module1','!module2',]

        ROUTE_MODULES = {
             '^/user/.*$':['httpmodule.loginmodule','!httpmodule.ipauth.ipblack',],
             'Index': ['!httpmodule.auth.AuthModule',]
        }
      

      路由处理器为一个字典,字典的键为需要匹配的路由的名称(定义urls时指定),或路由path的正则表达式,如上例。 值为处理该路由请求的模块。 在请求过程中,满足匹配条件的路由处理器将被在指定过程触发,根据模块实现的方法来进行相应的处理。 如果在配置模块的前面添加了 ! 符号,将反选在COMMON_MODULES中同名的模块,那么在请求过程中,全局处理器将不再匹配的路由中执行。

      • 当你需要对某个路由禁用全部的 COMMON_MODULES 模块处理器时,你不需要写很多!,你只需要配置一条 !all 即可:

          ROUTE_MODULES = {
               '^/user/.*$':['httpmodule.loginmodule','!all',],
          }
        

        !all 将会禁用 COMMON_MODULES 定义的全部处理器。由于 COMMON_MODULES 总是优先于路由处理器顺序执行,通过!all可以让你在 ROUTE_MODULES 中个性化你的路由处理器执行顺序,而其他的路由处理器配置不受影响。

        注: 在路由处理器配置中添加 ! 符号的处理器,必须存在于 COMMON_MODULES 中,否则将引起异常。

      如上实例中,请求名为Index 的路由将不执行 COMMON_MODULES 中配置的 httpmodule.auth.AuthModule 模块,请求满足 ^/user/.*$ 正则的路由不执行 httpmodule.ipauth.ipblack 模块。

  • ####缓存:

    tornadopy支持使用memcache,redis,file,localcache作为缓存。缓存模块主要抽取自django.cache,相关配置可参考 Django文档,redis是新增支持。

    • redis缓存模块配置,例如:

        'rediscache': {
            'BACKEND': 'tornadopy.cache.backends.rediscache.RedisCache',
            'LOCATION': '127.0.0.1:6379',
            'OPTIONS': {
                'DB': 0,
                'PARSER_CLASS': 'redis.connection.DefaultParser',
                'POOL_KWARGS': {
                    'socket_timeout': 2,
                    'socket_connect_timeout': 2
                },
                'PING_INTERVAL': 120  # 定时ping redis连接池,防止被服务端断开连接(s秒)
            }
        },	
      

      redis配置中,BACKEND 支持两种:

      tornadopy.cache.backends.rediscache.RedisCachetornadopy.cache.backends.rediscache.RedisClient

      RedisClient提供一个原生的client属性,提供基础的,原生的redis-py功能,而RedisCache 继承自 RedisClient 是提供高层缓存使用,其实现了和 tornadopy.cache.backends.memcached.MemcachedCache相同的接口,且行为和功能一致。如果你需要一些高级的redis方法,请使用RedisClient,如果仅仅需要基础的缓存功能,使用RedisCache即可。RedisCache同样提供client属性。

  • ####DB&ORM:

    tornadopy提供了对SqlAlchemy ORM的支持,模块tornadopy.db.dbalchemy对sqlalchemy进行了基本的封装使其更加易用。同时,tornadopy提供了一个简单轻量级的db模块basedb,此模块来自与web.py框架的db模块,基本的使用方式可以参考web.py cookbook,下面主要介绍dbalchemy模块。

    数据库配置:

      DATABASE_CONNECTION = {
          'default': {
              'connections': [{
                                  'ROLE': 'master',#主库
                                  'DRIVER': 'mysql+mysqldb',
                                  'UID': 'root',
                                  'PASSWD': '',
                                  'HOST': '',
                                  'PORT': 3306,
                                  'DATABASE': '',
                                  'QUERY': {"charset": "utf8"}
      
                              },
                              {
                                  'ROLE': 'slave',#从库,可配置多个
                                  'DRIVER': 'mysql+mysqldb',
                                  'UID': 'root',
                                  'PASSWD': '',
                                  'HOST': '',
                                  'PORT': 3306,
                                  'DATABASE': '',
                                  'QUERY': {"charset": "utf8"}
                              }]
          }
      }
    

    PING_DB:定时对数据库进行ping操作,保持连接池可用。默认:500s

    sqlalchemy配置,列出部分,可自行参考sqlalchemy文档增加配置项,该配置项对所有连接全局共享。

      SQLALCHEMY_CONFIGURATION = {
          'sqlalchemy.connect_args': {
      			'connect_timeout': 3 
      	 },
          'sqlalchemy.echo': False, #开启打印sql日志
          'sqlalchemy.max_overflow': 10,
          'sqlalchemy.echo_pool': False,
          'sqlalchemy.pool_timeout': 5,
          'sqlalchemy.encoding': 'utf-8',
          'sqlalchemy.pool_size': 100,
          'sqlalchemy.pool_recycle': 3600,
          'sqlalchemy.poolclass': 'QueuePool'  # 手动指定连接池类
      }
    

    使用方式:

      from tornadopy.db.dbalchemy import Model
      from sqlalchemy import *
      from sqlalchemy.dialects.mysql import INTEGER
      
      
      class BaseModel(Model):
          __abstract__ = True
          __connection_name__ = 'default' #对应配置中的default项
      
          ID = Column('id', INTEGER(11, unsigned=True), primary_key=True, nullable=False)  # primary key
    
    
      class User(BaseModel):
    
          __tablename__ = 'users'
      
          name = Column(String(10), nullable=False)
          password = Column(String(64), nullable=False)
    
    • 查询:如上,Model对象的Q属性提供一个默认简单的查询对象,你可以像这样 User.Q.filter(User.name='jack').all() 。 也可以像这样:User.session.query(User) 使用session属性创建查询对象。

    当存在主从数据库时,执行增删改操作需要指明使用主库的会话对象: session = User.session.using_master()

    • 分页:

        query = User.Q.all()  
        pagelist_obj = query.paginate(page=1, per_page=10, default=None)  
        total = pagelist_obj.total  
        page = pagelist_obj.page  
        items = pagelist_obj.items
      

    使用Sqlalchemy必须在配置中间件中加入:tornadopy.middleware.dbalchemy.DBAlchemyMiddleware

  • ####异步线程池

    tornado本身是异步单线程单进程框架,这样当遇到使用mysql的慢查询时,就会阻塞进程。tornadopy提供一个简单的方式来用线程池包装同步方法。通过配置文件设定 THREADS_NUM 数量来决定线程池的最大线程数,默认为cpu_count。

    注:新版tornado中内置了 concurrent.run_on_executor 装饰器,可提供同样的功能,tornadopy提供 tornadopy.decorators.async_execute 来方便使用线程池来异步化你的同步方法。

      	from tornadopy.decorators.async_execute import async_execute
      	class Test(Base):
      	    @coroutine
      	    def get(self):
      	        a=''
      	        b=''
      	        #支持使用gen的task模块来同步化异步调用
      	        result = yield self.dosomething(a, b)
      	        self.finish(result)
      	
      	    @async_execute
      	    def dosomething(self,a,b):
      	        # 这里可能耗时很久
      	        # something...
      	        result='return'
      	        return result
    
  • ####session:

    tornadopy提供一个简单的session功能,session可以使用tornadopy.cache下的缓存模块或实现了 tornadopy.cache.backends.base.BaseCache 的模块类作为session_store,比如你可以使用memcache、redis或LocalCache缓存来作为session的存储。

    首先,你需要增加中间件 tornadopy.middleware.session.SessionMiddleware 来开启对session的支持,在具体的路由handler中,可以通过handler.session获取session存储对象。

    session配置:

      SESSION = {
          'session_cache_alias': 'default',  # 'session_loccache',对应cache配置名
          'session_name': '__TORNADOSSID',
          'cookie_domain': '',
          'cookie_path': '/',
          'expires': 0,  # 24 * 60 * 60, # 24 hours in seconds,0代表浏览器会话过期
          'ignore_change_ip': False,
          'httponly': True,
          'secure': False,
          'secret_key': 'fLjUfxqXtfNoIldA0A0J',
          'session_version': 'EtdHjDO1'
      }
    

    session使用: 你可以像这样读写session:

      	class LoginHandler(WebHandler):
      		def get(self,uid):
      			self.session['userid'] = uid
      			self.set_expire(3600 * 24 * 30) #30天
    
      	class AuthHandler(WebHandler):
      		def get(self,uid):
      			uid = self.session['userid']
    
      	class LogoutHandler(WebHandler):
      		def get(self,uid):
      			del self.session['userid']
    
  • ####token:

    tornadopy提供一个token功能,token只可以使用tornadopy.cache下的redis缓存模块来实现。

    首先,你需要增加中间件 tornadopy.middleware.token.TokenMiddleware 来开启对token的支持,在具体的路由handler中,可以通过handler.token获取token存储对象。

    注意:其实把token模块做成HTTP处理器更优雅。

    token配置:

      TOKEN = {
          'token_cache_alias': 'default_redis',  # 此处必须是 default_redis
          'ignore_change_ip': False,
          'token_timeout': 2592000,
          'secret_key': 'xxxxxxxxxxxxxxxxxxxx',
          'token_version': ''
      }
    

    token使用: 你可以像这样使用token:

      	class LoginTokenHandler(WebHandler):
      	    def get(self):
      	        userID = self.get_argument("userID")
      	        userName = self.get_argument("userName")
    
      	        tmp_data = {
      	            "userID": userID,
      	            "userName": userName
      	        }
    
      	        tokenID = self.token.save(tmp_data)
      	        self.write(tokenID)
    
      	class LoginTokenTestHandler(WebHandler):
      	    def get(self):
      	        if self.token.get_current_user() == None:
      	            self.write("tokenID 非法")
      	        else:
      	            self.write("tokenID 是合法的")
    
  • ####signal:

    信号组件提供信号的注册与通知处理能力,我们可以在任何地方注册事件,也可以在你希望的任何时候触发事件。在信号触发时,将调用接收信号的callback,进行相关业务逻辑处理。

    tornadopy提供了几个与请求过程相关的信号,这几个信号通过信号中间件触发。他们分别是 call_started ,handler_started , handler_response , call_finished , handler_render ,触发事件分别对应中间件 process_call , process_request , process_response , process_endcall , process_render 几个过程 。

    使用:

      from tornadopy.signal import call_started,handler_render
    
      class MyService(object):
    
      	# 通过装饰器来注册事件回调
          @receiver(call_started)
          def callback(**kwargs):
              """do something..."""
    
      def callback(**kwargs):
      	print kwargs
    
      # 通过调用信号connect方法注册事件回调
      handler_render.connect(callback)
    

    事件回调函数接收一个 **kwargs 参数,在事件触发时,kwargs包含事件的 signal对象,事件源的class,事件参数等。

    自定义信号事件:

      from dispatch import Signal
      	
      my_event = Signal(providing_args=["args1"])
    
      # 事件触发
      my_event.send(sender=somesender.__class__, args1=arg)
    
You can’t perform that action at this time.