Flask中有兩種上下文,請求上下文和應用上下文。
請求上下文(request context)
request和session都屬於請求上下文對象。
request:封裝了HTTP請求的內容,針對的是http請求。舉例:user = request.args.get('user'),獲取的是get請求的參數。
session:用來記錄請求會話中的信息,針對的是用戶信息。舉例:session['name'] = user.id,可以記錄用戶信息。還可以通過session.get('name')獲取用戶信息。
應用上下文(application context)
current_app和g都屬於應用上下文對象。
current_app:表示當前運行程序文件的程序實例。
g:處理請求時,用於臨時存儲的對象,每次請求都會重設這個變量。比如:我們可以獲取一些臨時請求的用戶信息。
當調用app = Flask(_name_)的時候,創建了程序應用對象app;
request 在每次http請求發生時,WSGI server調用Flask.call();然后在Flask內部創建的request對象;
app的生命周期大於request和g,一個app存活期間,可能發生多次http請求,所以就會有多個request和g。
最終傳入視圖函數,通過return、redirect或render_template生成response對象,返回給客戶端。
區別: 請求上下文:保存了客戶端和服務器交互的數據。 應用上下文:在flask程序運行過程中,保存的一些配置信息,比如程序文件名、數據庫的連接、用戶信息等。
上下文對象的作用域
在flask項目中某一個功能中會有多個視圖,那么from flask import request,current_app,session,g,怎么保證某次請求的上下文不會被別的視圖拿走呢?
從pycharm中進入globals.py:
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))
線程有個叫做ThreadLocal的類,也就是通常實現線程隔離的類。而werkzeug自己實現了它的線程隔離類:werkzeug.local.Local。LocalStack就是用Local實現的。
LocalStack是flask定義的線程隔離的棧存儲對象,分別用來保存應用和請求上下文。
它是線程隔離的意思就是說,對於不同的線程,它們訪問這兩個對象看到的結果是不一樣的、完全隔離的。這是根據pid的不同實現的,類似於門牌號。
而每個傳給flask對象的請求,都是在不同的線程中處理,而且同一時刻每個線程只處理一個請求。所以對於每個請求來說,它們完全不用擔心自己上下文中的數據被別的請求所修改。
而這個LocalProxy 的作用就是可以根據線程/協程返回對應當前協程/線程的對象,也就是說
線程 A 往 LocalProxy 中塞入 A
線程 B 往 LocalProxy 中塞入 B