tornado: web.py 之 Application

当初之所以突然捡起python以及体验tornado,源自忘了哪里看到的一篇文章,说tornado十一个简洁高效的web server以及框架,总共代码两千多行,所以懒人义无反顾的抱起来研究。

上次说的那个Options还好,不小心打开了web.py,尼嘛,光这个一个文件就超过两千行(2.4.1),坑爹啊。。。谁乱说的来着?

考虑到这个文件尼嘛太大了,所以分开研究,依旧是看点儿写点儿。。。所以这一篇只记录Application这个类。

 

基本上所有的tornado的入门的文章都逃不出这个例子,当然,这篇也不能例外:

 

        application = web.Application([
            (r"/", MainPageHandler),
        ])
        http_server = httpserver.HTTPServer(application)
        http_server.listen(8080)
        ioloop.IOLoop.instance().start()

 

 

很明显,在这个例子中tornado依赖于Application类构造函数中的参数来构建路由映射规则,那这个参数有几个特点:

  1. 列表
  2. 每一个列表项都是一个元组
  3. 每一个元组至少包含了两个参数(为什么说至少,是因为其实还可以包含第三个参数)
  4. 元组的第一项是一个正则表达式,用来定义路由的filter
  5. 元组的第二项是一个类,tornado会用这个类的实例来处理相应的路由映射

所以,按照上面的分析,很容易根据需要定义出自己的路由规则表,借用tornado中blog的例子:

 

(r"/", HomeHandler),
(r"/archive", ArchiveHandler),
(r"/feed", FeedHandler),
(r"/entry/([^/]+)", EntryHandler),
(r"/compose", ComposeHandler),
(r"/auth/login", AuthLoginHandler),
(r"/auth/logout", AuthLogoutHandler),

根据传说中的common sense,所有路由规则中包含wildcard字符的路由规则项,他们在tornado处理的时候,会赋给较低的优先级,毕竟我们不想(.*)$这样的路由规则抢了其他所有人的饭碗,就像这个。。。。。

写道
本人兼职:苦力搬运,装卸,车工,钳工,焊工,水电工,泥瓦工,砸墙,砌墙,筛沙,油漆,通下水道,贴瓷砖,室内装璜,Vb,C++,.NET,C#,Java,j2ee,j2me,asp,php,jsp,delphi,汇编,PC&手机游戏开发,网络维护管理,三维建模,照片上色,平面设计,建筑效果图,机械与模具设计,flash动画,硬件设计,单片机开发,嵌入式系统,PLC编程与控制,盗版DVD,四六级替考,私人侦探,出租男女友,婚介,办证,黑枪,黑车,暗杀,洗钱,要债,洗头,搓澡,按摩,刮痧,拔火罐,算命,纹身,绣眉,画指甲,丰胸,割双眼皮,处女膜修复,人工受精,维修核潜艇,回收二手航母、二手航天飞机,大修核反应堆,拆洗导弹发动机更换机油,无人侦察机手动挡改自动,航天飞机保养换三滤,飞碟外太空年检 ,各型号导弹加装迎宾踏板,高空作业擦洗卫星表面除尘、打蜡及抛光,批发歼10,F22,F35,B2轰炸机,氢弹,原子弹,中子弹,东风全系列巡航导弹。并提供原子对撞机,提供捕捉反物质原子、虫洞修复技术支持。量大从优,团购7折,秒杀5折,根据国家三包规定7天包退、15天包换、一年保修,有正规发票

 

 

 

当然,对于好学的我必须很好奇,除了这个参数之外,还有其他的可选项嘛?所以来看看Application类的构造函数,不过具体的代码和分析就不写了,太长。。。要打好多字。。。

 

Application构造函数接受的其他参数:

  1. default_host。当tornado接受到request但是没有指定handler或者没有能够匹配的handler的时候,使用default_host做自动跳转。(不过看了一下Application的构造函数,总觉得不科学啊。。唯一能够触发这种场景的例子貌似就是一个handler都不加,否则想像不出来神码东西可以逃出.*$这样的黑洞。。。)
  2. transforms。也不知道干啥的
  3. wsgi。更不知道干啥的。。。
  4. settings。这个我知道,可以包含对于Application这个web server的配置项,这个太长,放到下一个小标题讲。

默认Application会处理的Settings项:

  1. gzip。一旦指定gzip,会自动添加一个GZipContentEncoding,用来处理被GZip压缩过的数据。
  2. ui_modules。不知到是干啥的。。。不过tornado会自己自动添加三个UI Modules:linkify, xsrf_form_html, Template。
  3. ui_methods。尼嘛还是不知到是干嘛地。。。。
  4. debug。用来保证tornado运行在debug模式
  5. static_path。服务器端存放静态文件(图像,CSS,etc.)的相对目录。如果指定了static_path,tornado就会接着在settings中寻找其他几个配置项,包含:
    static_url_prefix: 从当前位置指向包含静态文件的目录的“相对路径”
    static_handler_class: 类,其实例用来处理客户端对于静态文件的请求
    static_handler_args: 字典,包含用来初始化
    static_handler_class实例,所需要的参数

需要注意的是,不管你愿不愿意,tornado都会帮你自动添加如下四个路由映射规则:

  1. $static_path/(.*) ---> static_handler_class
  2. /favicon.icon      ---> static_handler_class
  3. /robots.txt          ---> static_handler_class
  4. .*$                      --->所有传入Application构造函数的handler

--------------------------------------------------------------------------------------------------------------2013-1-24

补充一下,在handler中提到,还可以定义以下的settings项:

    if "template_loader" in settings:
        return settings["template_loader"]
    kwargs = {}
    if "autoescape" in settings:
        # autoescape=None means "no escaping", so we have to 
         be sure
        # to only pass this kwarg if the user asked for it.
        kwargs["autoescape"] = settings["autoescape"]

 ---------------------------------------------------------------------------------------------------------------------------------------------------------

 

嗯,默认的行为就是这样了,如果你有特别的需求,可以自定义一个Application,通过继承默认的类Application。还是来自blog的例子:

 

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/", HomeHandler),
            (r"/archive", ArchiveHandler),
            (r"/feed", FeedHandler),
            (r"/entry/([^/]+)", EntryHandler),
            (r"/compose", ComposeHandler),
            (r"/auth/login", AuthLoginHandler),
            (r"/auth/logout", AuthLogoutHandler),
        ]
        settings = dict(
            blog_title=u"Tornado Blog",
            template_path=os.path.join(os.path.dirname(__file__), "templates"),
            static_path=os.path.join(os.path.dirname(__file__), "static"),
            ui_modules={"Entry": EntryModule},
            xsrf_cookies=True,
            cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
            login_url="/auth/login",
            autoescape=None,
        )
        tornado.web.Application.__init__(self, handlers, **settings)

        # Have one global connection to the blog DB across all handlers
        self.db = tornado.database.Connection(
            host=options.mysql_host, database=options.mysql_database,
            user=options.mysql_user, password=options.mysql_password)

上面高亮的部分,或者会被tornado其他的地方用到 (比如xsrf_cookies),或者会被用户自己的代码用到(比如blog_title),反正构造函数不管就是了。

 

 

构造函数了解了,然后顺便看看Application类的其他方法们:

  • listen。根据给出的参数启动一个HTTPServer,关于这个方法,有两个注意事项:1. For advanced uses (e.g. preforking), do not use this method; create an HTTPServer and call its bind/start methods directly. 2. Note that after calling this method you still need to call IOLoop.instance().start() to start the server.
  • add_handler。如果你在Application初始化之后后悔了,想要添加其他的路由映射关系,那就调用这个方法吧!根据上面所说的,含有wildcard字符的路由映射会拥有较低的优先级(其实Application会维护一个handler的列表,每次在规则表中查找映射的时候总是从第一个开始依次遍历,所谓低优先级,就是处在列表尾端而已)
  • add_transform。Again,不知道干啥地。。。
  • _get_host_handlers。顾名思义,如果目有找到,返回None。
  • _load_ui_methods。貌似是从一个或一些UIModule里面把所有的uimethod导入到Application类实例中的self.ui_methods里面。不过不知道意义何在。。。
  • _load_ui_modules。把一个或一些UIModule备份在Application类实例中的self.ui_modules里面。也不知道干啥用。。。收藏癖?
  • __call__。这个好,在第一个提到的listen方法里面,会把当前application实例(调用listen的那个)作为参数传入HttpServer,既然Application知道的太多,HttpServer显然会把它往死了用。基本上HttpServer自己只管在门口拉客放风,客人来了具体怎么找到对客人胃口的小姐那就是Application这个老鹞的事情了(主要逻辑就是__call__函数中)。。。。而具体办事,老鹞是不亲自上阵的(客人想也不行!),客人满意不满意完全依赖于各位小姐(各个Handler)自己的本事。。。
  • reverse_url。不懂
  • log_request。这还用说么?我觉得还是要说。主要是,开发者可以通过传入Application的Settings来自定义log方法;否则使用默认的logging。

 

猜你喜欢

转载自9esuluciano.iteye.com/blog/1773495