tornado 学习笔记6 Application 源码分析

      Application 是Tornado重要的模块之一,主要是配置访问路由表及其他应用参数的设置。

      源代码位于虚拟运行环境文件夹下(我的是env),具体位置为env > lib>sit-packages>tornado>web.py。

     image

     注释大体意思:

        Application是由请求handlers集合组成,配置好application之后,直接作为参数传递给HTTPServer。

       这个类的构造函数包含URLSpec对象集合或者(正则表达式,request handler)元组集合。当服务器接收到请求时,我们会按顺序迭代循环集合,找到第一个与请求路径相匹配的正则表达式对应的配置项,然后实例化配置项中对应的hanlder对象。

       当然,tornado也支持虚拟主机,就是使用add_handles方法,使用主机正则表达式作为第一个参数。

6.1 构造函数

     定义:

     def __init__(self, handlers=None, default_host="", transforms=None,
              **settings):

    参数:

  • hanlders:为配置的URLSpec集合或者(正则表达式,hanlder)元组集合
  • default_host:默认的服务器名称。(暂时不知道干什么用的)
  • transforms:转换。是一个集合,内容转换处理器集合。用来对响应的内容进行转换处理,比如压缩处理。
  • settings:配置字典。

    主要处理过程:

          (1) 对静态文件的处理。

#如果在设置中配置了static_path参数
if self.settings.get("static_path"):
    #得到static_path参数值
    path = self.settings["static_path"]
    handlers = list(handlers or [])
    #得到static_url_prefix参数值,默认值为/static/
    static_url_prefix = settings.get("static_url_prefix",
                                     "/static/")
    #得到static_handler_class参数值,也就是静态文件处理类,默认值为StaticFileHandler
    static_handler_class = settings.get("static_handler_class",
                                        StaticFileHandler)
    #得到static_handler_args参数值,其他参数
    static_handler_args = settings.get("static_handler_args", {})
    static_handler_args['path'] = path
    #1将以static_url_prefix为前缀的路径访问以及根目录下的favicon.ico和robots.txt组成正则表达式,
    #2并将这些正则表达式关联到static_handler_class作为元组
    #3将这些元组一个一个插入到hanlders集合的最前面
    for pattern in [re.escape(static_url_prefix) + r"(.*)",
                    r"/(favicon.ico)", r"/(robots.txt)"]:
        handlers.insert(0, (pattern, static_handler_class,
                            static_handler_args))

          因为tornado请求的都是由hanlder来处理,由hanlder决定怎么返回响应。静态文件比如css文件、图片文件、以及其他word、excel、txt等文件,当游览器访问这些静态文件时,需进行区别业务hanlder的处理方式。

举个例子:

          源码结构为:

clip_image002

          源代码为:

STATIC_ROOT = os.path.join(os.path.dirname(__file__), 'static').replace('\', '/')

settings = {

"static_path": STATIC_ROOT,

"static_url_prefix": "/static/",

'debug': True,

}

app = Application(handlers=[

url(r"/", MainHanlder),

url(r"/story/([0-9]+)", StoryHanlder, dict(db=db), name="story"),

], **settings)

            最后在游览器中访问style.css静态样式表文件。结果如下。

clip_image004

           当然,可以根据你项目自身的结构配置static_path、static_url_prefix两个参数。

          (2) 对handlers的处理

                if handlers:

               self.add_handlers(".*$", handlers)

               这里调用了add_handlers的方法。

          (3) 对设置参数情况的处理

if self.settings.get('debug'):

self.settings.setdefault('autoreload', True)

self.settings.setdefault('compiled_template_cache', False)

self.settings.setdefault('static_hash_cache', False)

self.settings.setdefault('serve_traceback', True)

# Automatically reload modified modules

if self.settings.get('autoreload'):

from tornado import autoreload

autoreload.start()

6.2 设置参数说明

Application可以设置的参数包括3种类型,分别是一般参数、授权和安全设置参数、模板参数、静态文件配置参数。

    一般参数:

  • l autoreload: 如果是True,当任何源文件改变时,服务器进程将会重新启动。这个选项只有在3.2版本有,以前这个功能被debug选项控制。
  • l debug: 设置成调试模式。debug = True 等同于 autoreload=True,compiled_template=False,static_hash_cache=False,serve_traceback=True.
  • l default_handler_class 以及default_handler_args: 如果没有找到相匹配的handler,会使用这个默认的handler.s使用这个可以自定义404页面。
  • l compresss_response: 如果设置成True.文本格式返回的响应会被压缩。在tornado 4.0版本才有这功能。
  • l gzip : 从4.0版本后过时,被compresss_response替代
  • l log_function :在每个请求响应之后,这个函数会被调用,用来记录结果。默认实现是写入到logging模块的跟日志记录器中。这个可以被自定义。
  • l serve_traceback: 如果设置成true. 默认的错误页面会包含错误跟踪。这个选项在3.2版本新增的。之前的版本通过设置debug=true来实现功能。
  • l ui_modules 和ui_methods:设置对ui 模板的 UIModule 或者UIMethods的映射。

    授权和安全设置参数:

  • l cookie_secret: 被RequestHandler.get_secure_cookie 和set_secure_cookie使用,用来签发cookies;
  • l login_url:如果用户没有登录,使用了authenticated装饰器的请求处理都会重定向到这个url.可以重写RequestHanlder.get_login_url进行进一步的自定义。
  • l xsrf_cookies: 如果设置成True,跨站(Cross-site)保护会被启动。

    模板参数:

  • l autoscape: 为模板控制自动转义。可以设置成None来禁用转义,或者设置成一个函数名称,这样所有的输出都会被传递。默认值为 xhtml_escape.可以通过 {% autoescape %}指令在每一个模板上进行改变;
  • l compiled_template_cache: 默认设置为True。如果设置成False,针对每个请求,每个模板都会重新编译。这个选项在3.2版本中新增,以前版本都是通过设置debug选项来实现。
  • l template_path :包含template文件的文件夹目录。可以重写 RequestHandler.get_template_path来进一步自定义。
  • l template_loader: 给tornado.template.BaseLoader设置一个实例,用来自定义模板的加载。如果这个选项设置了,那么template_path 以及 autoescape 这两个选项会被忽视。这个通过重写RequestHandler.create_template_loader来进一步实现自定义。

    静态文件设置:

  • l static_hash_cache: 默认值为True.如果为False,针对每一个请求,静态url将会被重新计算。这个选项是在3.2版本新增的。以前这个功能只能通过debug设置来控制。
  • l static_path: 静态文件所在目录。
  • l static_url_prefix:静态文件访问得url前缀。默认为:“/static”
  • l static_handler_class,static_handler_args: 可以使用自定义的静态文件处理器去替代默认的tornado.web.StaticFileHandler。static_handler_args,如果设置了,必须为一个字典,而且会被传递到handler的initialize方法作为参数。

6.3 add_handlers方法

在构造函数中处理中,有一个很重要的过程,就是对配置的handlers进行处理。就是add_hanlders方法。

这个方法的是将给定的hanlders追加到我们的hanlder列表中。

  • 方法定义:def add_handlers(self, host_pattern, host_handlers):
  • 参数:

             host_pattern: 虚拟主机匹配的正则表达式。Application默认设置为””

             host_handlers :要添加的handlers。

  • 源码分析:
if not host_pattern.endswith("$"):    host_pattern += "$"
handlers = []
# The handlers with the wildcard host_pattern are a special
# case - they're added in the constructor but should have lower
# precedence than the more-precise handlers added later.
# If a wildcard handler group exists, it should always be last
# in the list, so insert new groups just before it.
if self.handlers and self.handlers[-1][0].pattern == '.*$':
    self.handlers.insert(-1, (re.compile(host_pattern), handlers))
else:
    self.handlers.append((re.compile(host_pattern), handlers))

for spec in host_handlers:
    if isinstance(spec, (tuple, list)):
        assert len(spec) in (2, 3, 4)
        spec = URLSpec(*spec)
    handlers.append(spec)
    if spec.name:
        if spec.name in self.named_handlers:
            app_log.warning(
                "Multiple handlers named %s; replacing previous value",
                spec.name)
        self.named_handlers[spec.name] = spec

        方法主要逻辑是将handlers添加至Application的handlers属性中,但是添加的hanlder首先必须转换成URLSpec类型。如果hanlder配置了命名参数,检验名称的唯一性,并如果存在重复,将进行覆盖,并记录在日志中。

        通过 if isinstance(spec, (tuple, list)) 源码可以看出,hanlders的配置类型可以有两种类型,一种是元组集合,一种是列表,而如果是列表的话,那么列表中的项是URLSpec类型。而且每一handler是可以命名的。举个例子:Application的创建可以以下两个方式:

        方式一:hanlders用URLSpec对象列表传递,并且可以命名。

app = Application(handlers=[
    url(r"/", MainHanlder),
    url(r"/story/([0-9]+)", StoryHanlder, dict(db=db), name="story"),
], **settings)

        方式二:hanlders用元组集合传递

app = Application(handlers=[
    url(r"/", MainHanlder),
    url(r"/story/([0-9]+)", StoryHanlder, dict(db=db), name="story"),
], **settings)
原文地址:https://www.cnblogs.com/liaofeifight/p/4930398.html