tornado源碼分析-Application

來源:互聯網
上載者:User

標籤:tornado   python   web   源碼   

tornado.web包含web架構的大部分主要功能,Application是其中一個重要的類

Application類的作用是實現 URI 轉寄,將 Application 的執行個體傳遞給 httpserver ,當監聽到請求時,把伺服器傳回來的請求進行轉寄,通過調用 __call__ ,處理請求。

 

Application源碼:

class Application(httputil.HTTPServerConnectionDelegate):    """A collection of request handlers that make up a web application.    Instances of this class are callable and can be passed directly to    HTTPServer to serve the application::        application = web.Application([            (r"/", MainPageHandler),        ])        http_server = httpserver.HTTPServer(application)        http_server.listen(8080)        ioloop.IOLoop.instance().start()    The constructor for this class takes in a list of `URLSpec` objects    or (regexp, request_class) tuples. When we receive requests, we    iterate over the list in order and instantiate an instance of the    first request class whose regexp matches the request path.    The request class can be specified as either a class object or a    (fully-qualified) name.    Each tuple can contain additional elements, which correspond to the    arguments to the `URLSpec` constructor.  (Prior to Tornado 3.2, this    only tuples of two or three elements were allowed).    A dictionary may be passed as the third element of the tuple,    which will be used as keyword arguments to the handler's    constructor and `~RequestHandler.initialize` method.  This pattern    is used for the `StaticFileHandler` in this example (note that a    `StaticFileHandler` can be installed automatically with the    static_path setting described below)::        application = web.Application([            (r"/static/(.*)", web.StaticFileHandler, {"path": "/var/www"}),        ])    We support virtual hosts with the `add_handlers` method, which takes in    a host regular expression as the first argument::        application.add_handlers(r"www\.myhost\.com", [            (r"/article/([0-9]+)", ArticleHandler),        ])    You can serve static files by sending the ``static_path`` setting    as a keyword argument. We will serve those files from the    ``/static/`` URI (this is configurable with the    ``static_url_prefix`` setting), and we will serve ``/favicon.ico``    and ``/robots.txt`` from the same directory.  A custom subclass of    `StaticFileHandler` can be specified with the    ``static_handler_class`` setting.    """    def __init__(self, handlers=None, default_host="", transforms=None,                 **settings):        if transforms is None:            self.transforms = []            if settings.get("compress_response") or settings.get("gzip"):                self.transforms.append(GZipContentEncoding)        else:            self.transforms = transforms        self.handlers = []         self.named_handlers = {}        self.default_host = default_host        self.settings = settings        self.ui_modules = {'linkify': _linkify,                           'xsrf_form_html': _xsrf_form_html,                           'Template': TemplateModule,                           }        self.ui_methods = {}        self._load_ui_modules(settings.get("ui_modules", {}))        self._load_ui_methods(settings.get("ui_methods", {}))        if self.settings.get("static_path"):            path = self.settings["static_path"]            handlers = list(handlers or [])            static_url_prefix = settings.get("static_url_prefix",                                             "/static/")            static_handler_class = settings.get("static_handler_class",                                                StaticFileHandler)            static_handler_args = settings.get("static_handler_args", {})            static_handler_args['path'] = path            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))        if handlers:            self.add_handlers(".*$", handlers)        if self.settings.get('debug'): # 如果debug = True, 開啟autoreload 和 serve_traceback功能(出錯顯示錯誤資訊), 關閉compiled_template_cache和static_hash_cache<span style="font-family: Arial, Helvetica, sans-serif;">功能</span>            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'): # 服務能夠自動reload新的代碼            from tornado import autoreload            autoreload.start()    def listen(self, port, address="", **kwargs):        """Starts an HTTP server for this application on the given port.        This is a convenience alias for creating an `.HTTPServer`        object and calling its listen method.  Keyword arguments not        supported by `HTTPServer.listen <.TCPServer.listen>` are passed to the        `.HTTPServer` constructor.  For advanced uses        (e.g. multi-process mode), do not use this method; create an        `.HTTPServer` and call its        `.TCPServer.bind`/`.TCPServer.start` methods directly.        Note that after calling this method you still need to call        ``IOLoop.instance().start()`` to start the server.        接受連接埠,地址,其它參數        建立http伺服器並監聽該連接埠        """        # import is here rather than top level because HTTPServer        # is not importable on appengine        from tornado.httpserver import HTTPServer        server = HTTPServer(self, **kwargs)        server.listen(port, address)    def add_handlers(self, host_pattern, host_handlers):        """Appends the given handlers to our handler list.        Host patterns are processed sequentially in the order they were        added. All matching patterns will be considered.        """        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    def add_transform(self, transform_class):        self.transforms.append(transform_class)    def _get_host_handlers(self, request):        host = request.host.lower().split(':')[0]        matches = []        for pattern, handlers in self.handlers:            if pattern.match(host):                matches.extend(handlers)        # Look for default host if not behind load balancer (for debugging)        if not matches and "X-Real-Ip" not in request.headers:            for pattern, handlers in self.handlers:                if pattern.match(self.default_host):                    matches.extend(handlers)        return matches or None    def _load_ui_methods(self, methods):        if isinstance(methods, types.ModuleType):            self._load_ui_methods(dict((n, getattr(methods, n))                                       for n in dir(methods)))        elif isinstance(methods, list):            for m in methods:                self._load_ui_methods(m)        else:            for name, fn in methods.items():                if not name.startswith("_") and hasattr(fn, "__call__")                         and name[0].lower() == name[0]:                    self.ui_methods[name] = fn    def _load_ui_modules(self, modules):        if isinstance(modules, types.ModuleType):            self._load_ui_modules(dict((n, getattr(modules, n))                                       for n in dir(modules)))        elif isinstance(modules, list):            for m in modules:                self._load_ui_modules(m)        else:            assert isinstance(modules, dict)            for name, cls in modules.items():                try:                    if issubclass(cls, UIModule):                        self.ui_modules[name] = cls                except TypeError:                    pass    def start_request(self, connection):        # Modern HTTPServer interface        return _RequestDispatcher(self, connection)    def __call__(self, request):        # Legacy HTTPServer interface        dispatcher = _RequestDispatcher(self, None)        dispatcher.set_request(request)        return dispatcher.execute()    def reverse_url(self, name, *args):        """Returns a URL path for handler named ``name``        The handler must be added to the application as a named `URLSpec`.        Args will be substituted for capturing groups in the `URLSpec` regex.        They will be converted to strings if necessary, encoded as utf8,        and url-escaped.        根據name返回匹配的url路徑        """        if name in self.named_handlers:            return self.named_handlers[name].reverse(*args)        raise KeyError("%s not found in named urls" % name)    def log_request(self, handler):        """Writes a completed HTTP request to the logs.        By default writes to the python root logger.  To change        this behavior either subclass Application and override this method,        or pass a function in the application settings dictionary as        ``log_function``.        把HTTP請求寫進日誌        http狀態代碼小於400的為正常        大於等於400小於500<span style="font-family: Arial, Helvetica, sans-serif;">為</span><span style="font-family: Arial, Helvetica, sans-serif;">請求錯誤</span>        大於500是伺服器錯誤        """        if "log_function" in self.settings:            self.settings["log_function"](handler)            return        if handler.get_status() < 400:            log_method = access_log.info        elif handler.get_status() < 500:            log_method = access_log.warning        else:            log_method = access_log.error        request_time = 1000.0 * handler.request.request_time()        log_method("%d %s %.2fms", handler.get_status(),                   handler._request_summary(), request_time)



建構函式

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

它接受handlers (包含匹配規則和requesthandler的元組),default_host(預設主控件),transforms(輸出做分塊和壓縮的轉換)和setting(包含配置的字典)。

建立主機的路徑路由規則

 

方法

listen(self, port, address="", **kwargs) 建立http伺服器並監聽該連接埠

add_handlers(self, host_pattern, host_handlers)向handler列表中添加handler。host_pattern依次按照它們的添加順序進行處理,添加主機的路徑路由規則

add_transform(self, transform_class)向self.transforms增加transform_class,對輸出做分塊和壓縮的轉換

_get_host_handlers(self, request)尋找屬於這個request的handlers

_load_ui_methods(self, methods)在self.ui_methods中添加方法

_load_ui_modules(self, modules)在self.ui_modules中添加方法

reverse_url(self, name, *args)使用name返回匹配的url路徑

__call__(self, request) 在伺服器接受新串連時被調用 接受HttpRequest對象 根據 httprequest 調用execute 方法

start_request(self, connection)作用同__call__

log_request(self, handler)把HTTP請求寫進日誌。


debug=True 時代碼動態自動編譯的原理

Application 對象執行個體化時,給出“debug=True”參數的話,開啟autoreload 和 serve_traceback功能(出錯顯示錯誤資訊) , 關閉compiled_template_cache和static_hash_cache功能  


autoreload:改變原始碼的時候,伺服器處理序將能夠自動reload新的代碼並重啟。

serve_traceback:如果開啟,在出錯的時候就不是返回預設的錯誤頁面,取而代之的是顯示python的traceback,利用這個我們可以看到在什麼地方出現了錯誤,可以進行方便的調試。

compiled_template_cache:編譯模板緩衝,如果關閉,在重新整理時伺服器的模板都會重新載入。

static_hash_cache:靜態雜湊緩衝,如果關閉,在重新整理時有static_url()的地方都會重新載入需要讀取的static下的檔案,而不是用已經緩衝了的檔案。

tornado源碼分析-Application

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.