小辣椒開發日記

3927發表於2020-05-31

小辣椒開發筆記

應用啟動流程

根據WSGI協議,應用程式會接收到web server提供的environ與start_response兩個引數,我們只需要從environ引數中提取相關資訊並返回一個可迭代物件即可。

flask對該流程的處理邏輯如下:

def wsgi_app(self, environ, start_response):
    
    #根據提供的environ建立請求上下文物件,併入棧
    ctx = self.request_context(environ)
    ctx.push()
    error = None

    try:
        # 正確的請求處理路徑,會通過路由找到對應的處理函式
        response = self.full_dispatch_request()
    except Exception as e:
        # 錯誤處理,預設是 InternalServerError 錯誤處理函式,客戶端會看到伺服器 500 異常
        error = e
        response = self.handle_exception(e)
    return response(environ, start_response)

首先對出入的environ引數建立一個RequestContext請求上下文物件,該物件包含著HTTP請求所含有的所有資訊。之後請求上下文建立成功後,會執行response = self.full_dispatch_request(),該語句會根據請求中的路由找到相應的處理函式來處理請求,並將該函式的返回值處理後生成response物件返回。在處理請求的過程中,若遇到了異常,則該異常會被捕獲並交給handle_exception(e)函式處理,該函式接受一個異常物件並返回一個response物件。之後獲取response物件後,呼叫該物件即可。(所以說我們的應用程式好像更像是一箇中介軟體?)

路由處理

    def dispatch_request(self):
        rule = request.url_rule
        return self.view_functions[rule.endpoint](**request.view_args)

由路由到函式的對映關係為路由->端點->函式,在werkzeug庫中已經提供了一系列的類供我們處理路由與端點的關係,而我們需要做的只是處理端點到函式的對映關係,該關係用一個字典即可輕鬆搞定。由程式碼可知我們會在生成request物件的時候根據路由獲取對應的端點,在處理請求的時候我們只需根據端點呼叫相應函式即可。而對於端點與函式的對映關係,我們提供了一個簡單的函式用於註冊:

    def add_url_rule(self, path, view_func, endpoint=None, methods=None):
        if endpoint is None:
            endpoint = view_func.__name__

        if methods is None:
            methods = getattr(view_func, "methods", None) or ("GET",)

        rule = Rule(path, endpoint=endpoint, methods=methods)
        self.url_map.add(rule)
        self.view_functions[endpoint] = view_func

異常處理

    def handler_exceptions(self, e):
        exc_type = type(e)

        if exc_type in self.handler_map:
            handler = self.handler_map.get(exc_type)
            return handler(e)
        else:
            raise e

請求處理過程中觸發異常的話,異常會被捕獲並交給該函式處理,該函式接受一個異常後,根據異常所屬的類檢視該異常的處理方式是否被註冊,若已被註冊,則將該異常拋給註冊的錯誤處理器處理,並返回響應。若未被註冊,則將異常再次丟擲,觸發程式錯誤。用於註冊錯誤處理器的函式如下:

    def register_error_handler(self, exc_class_or_code, handler):
        exc_class = _find_exceptions(exc_class_or_code)
        self.handler_map[exc_class] = handler

相關文章