国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

將tornado改成rails的風格形式,并可以設置隱藏參數(shù)

2019-11-14 17:30:42
字體:
來源:轉載
供稿:網友

轉載請注明: TheV

先看下tornado的風格

請求時/main時,如果請求方法是post,則執(zhí)行MainHandler里面的post方法。。。。。

這樣感覺用著很不習慣。就只有

"GET", "HEAD", "POST", "DELETE", "PATCH", "PUT",
"OPTIONS"

這幾個方法,而且還不是由url體現(xiàn)出來的。

說下我的做法。由于是hack tornado的源碼,所以有必要簡單看下tornado的運行流程。

主要是在web.py里面。這里不討論tornado是怎么實現(xiàn)一個高性能,非阻塞的 http 服務器,只簡單說下他是怎么匹配映射然后執(zhí)行的。

Application類

class Application(object):        def __init__(self, handlers=None, default_host="", transforms=None,                 wsgi=False, **settings):        if transforms is None:            self.transforms = []            if settings.get("gzip"):                self.transforms.append(GZipContentEncoding)            self.transforms.append(ChunkedTransferEncoding)        else:            self.transforms = transforms        #保存配置handlers中處理的類,此時列表中的類還沒實例化        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._wsgi = wsgi        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'):            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') and not wsgi:            from tornado import autoreload            autoreload.start()    def listen(self, port, address="", **kwargs):        # import is here rather than top level because HTTPServer        # is not importable on appengine        #開啟服務器監(jiān)聽        from tornado.httpserver import HTTPServer        server = HTTPServer(self, **kwargs)        server.listen(port, address)    def add_handlers(self, host_pattern, host_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)                #創(chuàng)建映射url與handler的類,URLSpec類中有實例過的handler                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 __call__(self, request):        """Called by HTTPServer to execute the request."""        #請求從這里進入        transforms = [t(request) for t in self.transforms]        handler = None        args = []        kwargs = {}        handlers = self._get_host_handlers(request)        if not handlers:            handler = RedirectHandler(                self, request, url="http://" + self.default_host + "/")        else:            #例子走這里            for spec in handlers:                #遍歷,依次匹配                match = spec.regex.match(request.path)                #匹配成功                if match:                    #實例過的handler                    handler = spec.handler_class(self, request,*args,**kwargs)                    if spec.regex.groups:                        # None-safe wrapper around url_unescape to handle                        # unmatched optional groups correctly                        def unquote(s):                            if s is None:                                return s                            return escape.url_unescape(s, encoding=None,                                                       plus=False)                        # Pass matched groups to the handler.  Since                        # match.groups() includes both named and unnamed groups,                        # we want to use either groups or groupdict but not both.                        # Note that args are passed as bytes so the handler can                        # decide what encoding to use.                        if spec.regex.groupindex:                            kwargs = dict(                                (str(k), unquote(v))                                for (k, v) in match.groupdict().items())                        else:                            args = [unquote(s) for s in match.groups()]                    break            if not handler:                if self.settings.get('default_handler_class'):                    handler_class = self.settings['default_handler_class']                    handler_args = self.settings.get(                        'default_handler_args', {})                else:                    handler_class = ErrorHandler                    handler_args = dict(status_code=404)                #不會走這里                handler = handler_class(self, request, **handler_args)        # If template cache is disabled (usually in the debug mode),        # re-compile templates and reload static files on every        # request so you don't need to restart to see changes        if not self.settings.get("compiled_template_cache", True):            with RequestHandler._template_loader_lock:                for loader in RequestHandler._template_loaders.values():                    loader.reset()        if not self.settings.get('static_hash_cache', True):            StaticFileHandler.reset()        #準備開始執(zhí)行類中的方法        if issubclass(spec.handler_class,tornado.websocket.WebSocketHandler):        #如果handler_class是websocket的子類,這里必須要這個,否則       #不能用websocket,因為websocket里面重寫了_execute方法            handler._execute(transforms,*args, **kwargs)        else:            handler._execute(transforms,spec,*args, **kwargs)        return handler

 

__init__()里面就是保存設置,設置默認。注意里面有個add_handlers()。

進入add_handlers(),里面主要是對每個映射規(guī)則創(chuàng)建一個URLSpec類。這個類是專門保存映射規(guī)則和實例化handler類的,是hack的重點對象,這個后面會講到。

然后就是__call__(self, request),這個可以理解為請求的入口,里面注釋寫的很詳細了。

關于__call__和__init__ ,可以看下http://stackoverflow.com/questions/9663562/what-is-difference-between-init-and-call-in-python。

URLSpec類

class URLSpec(object):    """Specifies mappings between URLs and handlers."""    def __init__(self, pattern, handler, kwargs=None, name=None):        """Parameters:        * ``pattern``: Regular expression to be matched.  Any groups          in the regex will be passed in to the handler's get/post/etc          methods as arguments.        * ``handler_class``: `RequestHandler` subclass to be invoked.        * ``kwargs`` (optional): A dictionary of additional arguments          to be passed to the handler's constructor.        * ``name`` (optional): A name for this handler.  Used by          `Application.reverse_url`.        """        if not pattern.endswith('$'):            pattern += '$'        self.regex = re.compile(pattern)        assert len(self.regex.groupindex) in (0, self.regex.groups), /            ("groups in url regexes must either be all named or all "             "positional: %r" % self.regex.pattern)        if isinstance(handler, str):            # import the Module and instantiate the class            # Must be a fully qualified name (module.ClassName)            #實例化handler類            handler = import_object(handler)        #保存action        self.action=None        #如果配置中設置了action        if type(kwargs) is dict and 'action' in kwargs:            self.action=kwargs['action']        self.handler_class = handler        self.kwargs = kwargs or {}        self.name = name        self._path, self._group_count = self._find_groups()

回到__call__里面的最后handler._execute(transforms,spec, *args, **kwargs)。

這里我在_execute加了spec,為了在后面執(zhí)行handler類中方法時用到保存在spec中的action.

_execute在RequestHandler類中

   def _execute(self, transforms,spec, *args, **kwargs):        """Executes this request with the given output transforms."""        self._transforms = transforms        try:            if self.request.method not in self.SUPPORTED_METHODS:                raise HTTPError(405)            self.path_args = [self.decode_argument(arg) for arg in args]            self.path_kwargs = dict((k, self.decode_argument(v, name=k))                                    for (k, v) in kwargs.items())            # If XSRF cookies are turned on, reject form submissions without            # the proper cookie            if self.request.method not in ("GET", "HEAD", "OPTIONS") and /                    self.application.settings.get("xsrf_cookies"):                self.check_xsrf_cookie()            #設置當前的action,后面會用到            self.current_action=spec.action            #如果設置了隱藏參數(shù)            if 'param_keys' in spec.kwargs:                #將隱藏參數(shù)和實際請求中的參數(shù)一一對應                self.params=dict(zip(spec.kwargs['param_keys'],self.path_args));            self._when_complete(self.prepare(), self._execute_method)        except Exception as e:            self._handle_request_exception(e)    def _when_complete(self, result, callback):        try:            #不是長連接,走這里,執(zhí)行下面的_execute_method(self)            if result is None:                callback()            elif isinstance(result, Future):                if result.done():                    if result.result() is not None:                        raise ValueError('Expected None, got %r' % result.result())                    callback()                else:                    # Delayed import of IOLoop because it's not available                    # on app engine                    from tornado.ioloop import IOLoop                    IOLoop.current().add_future(                        result, functools.partial(self._when_complete,                                                  callback=callback))            else:                raise ValueError("Expected Future or None, got %r" % result)        except Exception as e:            self._handle_request_exception(e)    def _execute_method(self):        if not self._finished:            #默認的action是請求方法            method = getattr(self, self.request.method.lower())            if self.current_action:                #變成我的action                method = getattr(self, self.current_action)            #執(zhí)行            self._when_complete(method(*self.path_args, **self.path_kwargs),                                self._execute_finish)

最后的效果類似于

可以看到,路由規(guī)則并不是完全的ruby on rail那種,還是要自己寫需要指定映射的方法,框架只會幫你映射到類。

這樣的好處就是保有一定的靈活性。比如,像一般的登陸頁面,鏈接是'/login'就可以了,沒必要非要弄成"user/login".

tornado的源碼算是屬于很少很少的那種了。把復雜問題變簡單,這就是facebook工程師的境界。

最后附上例子 http://files.VEVb.com/TheViper/python_rails_style.zip 基于tornado 3.2.2

有個問題需要注意下,我用的是sublime text3,它是基于python3.3的,電腦裝的是python 2.7.運行的時候卻必須是print()的寫法才可以,否則報錯。。不知道是什么原因。

有知道的朋友請告訴我一聲。

 


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 托里县| 龙江县| 枝江市| 灯塔市| 溆浦县| 五峰| 自治县| 嘉禾县| 朝阳市| 涞水县| 集贤县| 新源县| 大厂| 兴业县| 清远市| 望奎县| 红桥区| 图木舒克市| 留坝县| 商丘市| 镇原县| 虎林市| 汝州市| 嘉兴市| 河池市| 商城县| 漳浦县| 镇平县| 焦作市| 新余市| 青冈县| 施甸县| 蒲城县| 邓州市| 尼玛县| 冷水江市| 望都县| 平度市| 衡山县| 广丰县| 津市市|