flask——request和response

當客戶端向服務器發送一個請求時,服務器會將請求轉發給web應用程序,應用程序處理完這個請求後將會返回一個response。在這篇文章我們分析一下flask怎樣處理request,又是怎樣生成response的,同時我們應該思考,在這個過程中,flask是怎樣讓url、endpoint、視圖函數一一對應的。

一旦web應用接收到request,flask就會調用Flask類的call函數。在wsgi_app()函數中,我們看到,在調用了full_dispatch_request()函數後,就生成了response(Response類實例)。

class Flask:
    def __call__(self, environ, start_response):
        return self.wsgi_app(environ, start_response)

    def wsgi_app(self, environ, start_response):
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                ctx.push()
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
           except:
               error = sys.exc_info()[1]
               raise
        return response(environ, start_response)
    finally:
        if self.should_ignore_error(error):
            error = None
        ctx.auto_pop(error)

在函數full_dispatch_request中,我們看到了dispatch_request函數,一路尋找下去,在這個函數裏找到了view_functions這個字典。這個字典被多個函數在多個函數中出現。

def full_dispatch_request(self):
    self.try_trigger_before_first_request_functions()
    try:
        request_started.send(self)
        rv = self.preprocess_request()
        if rv is None:
            rv = self.dispatch_request()
    except Exception as e:
        rv = self.handle_user_exception(e)
    return self.finalize_request(rv)

def dispatch_request(self):
    req = _request_ctx_stack.top.request
    if req.routing_exception is not None:
    self.raise_routing_exception(req)
    rule = req.url_rule

    if getattr(rule, 'provide_automatic_options', False) \
        and req.method == 'OPTIONS':
        return self.make_default_options_response()
return self.view_functions[rule.endpoint](**req.view_args)

self.view_functions = {}

那這個add_url_rule函數又是在哪裏被調用的呢?往下看。

def add_url_rule(self, rule, endpoint=None, view_func=None,provide_automatic_options=None, **options):
    if endpoint is None:
        endpoint = _endpoint_from_view_func(view_func)
        options['endpoint'] = endpoint
        methods = options.pop('methods', None)

# if the methods are not given and the view_func object knows its
# methods we can use that instead. If neither exists, we go with
# a tuple of only ``GET`` as default.
    if methods is None:
        methods = getattr(view_func, 'methods', None) or ('GET',)
    if isinstance(methods, string_types):
        raise TypeError('Allowed methods have to be iterables of strings, ''for example: @app.route(..., methods=["POST"])')
    methods = set(item.upper() for item in methods)

# Methods that should always be added
    required_methods = set(getattr(view_func, 'required_methods', ()))

# starting with Flask 0.8 the view_func object can disable and
# force-enable the automatic options handling.
    if provide_automatic_options is None:
        provide_automatic_options = getattr(view_func,'provide_automatic_options', None)

    if provide_automatic_options is None:
        if 'OPTIONS' not in methods:
            provide_automatic_options = True
            required_methods.add('OPTIONS')
        else:
            provide_automatic_options = False

        # Add the required methods now.
        methods |= required_methods

        rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options

        self.url_map.add(rule)
        if view_func is not None:
            old_func = self.view_functions.get(endpoint)
                if old_func is not None and old_func != view_func:
                    raise AssertionError('View function mapping is overwriting an ''existing endpoint function: %s' % endpoint)
            self.view_functions[endpoint] = view_func

看到這裏就應該明白了。在我們寫的web應用程序中,往往需要對視圖函數添加路由修飾,如:app.route(‘/’)。正是在路由函數中調用了add_url_rule函數,而這個函數負責綁定相應的視圖函數、url、以及endpoint。由此,這三個參數建立聯繫。而後,在程序運行中,當web程序收到請求後,根據請求中的url找到endpoint,再根據endpoint找到視圖函數,然後調用視圖函數,在視圖函數中,會處理那些需要處理的值(return self.view_functionsrule.endpoint)。接下來這個函數的返回值會交給finalize_request()函數處理。

def route(self, rule, **options):
    def decorator(f):
        endpoint = options.pop('endpoint', None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f
    return decorator

正是在這個函數裏,生成了response。(response是Response類的實例),最終,這個response被返回給客戶端,然後顯示爲頁面。

def finalize_request(self, rv, from_error_handler=False):
    response = self.make_response(rv)
    try:
        response = self.process_response(response)
        request_finished.send(self, response=response)
    except Exception:
        if not from_error_handler:
        raise
            self.logger.exception('Request finalizing failed with an ''error while handling an error')
    return response
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章