前言
應用上下文和請求上下文存在的目的,官方文檔講的很清楚,可參考:html
http://www.pythondoc.com/flask/appcontext.htmlpython
應用上下文對象在沒有請求的時候是能夠單獨存在的,可是請求上下文對象只有在收到請求後纔會被建立。請求處理和應用上下文和請求上下文的關係是:json
接收請求--》建立請求上下文--》請求上下文入棧--》建立該請求的應用上下文--》應用上下文入棧--》處理邏輯--》請求上下文出棧--》應用上下文出棧flask
系列文章
-
flask基礎之jijia2模板使用基礎(二)cookie
-
flask基礎之jijia2模板語言進階(三)session
請求上下文RequestContext
請求上下文管理着請求對象Request,會話對象Session,當前請求的app應用,爲了保證在一個請求的週期內的任什麼時候候任何地點訪問到Request和Session,又不能發生循環導入的問題,flask使用代理對象request和session來代理當前請求的Request和Session。框架
request = LocalProxy(partial(_lookup_req_object, 'request')) session = LocalProxy(partial(_lookup_req_object, 'session'))
RequestContext分析
flask框架處理請求的第一步就是收到請求後建立請求上下文RequestContext.
class RequestContext(object): def __init__(self, app, environ, request=None): self.app = app if request is None: request = app.request_class(environ) # 使用app的Request對象建立一個實例 self.request = request # 請求上下文的request self.url_adapter = app.create_url_adapter(self.request) self.flashes = None self.session = None # 請求上下文的session self._implicit_app_ctx_stack = [] # 請求上下文的應用上下文臨時存放點 self.preserved = False self._preserved_exc = None self._after_request_functions = [] self.match_request() # 提取請求的路由建立request對象的Rule對象
request
request做爲一個代理對象,其指向的是當前的請求的請求上下文RequestContext對象的request屬性,即在請求上下文初始化的時候建立的請求對象,它是程序處理邏輯頻繁須要的對象,存儲着幾乎全部的請求數據信息,本質上是Request對象。生命週期爲一次請求期間,當請求處理完成後被銷燬;
class Request(RequestBase): url_rule = None # 記錄本次請求的Rule對象 view_args = None # 本次請求的參數,指的是用路由轉化器獲得的參數 routing_exception = None # 若是路由匹配失敗,記錄錯誤對象 # 重要的屬性 request.max_content_length # 獲取該請求容許的數據包最大字節數 request.endpoint # 獲取該請求的rule的標識符 request.url_charset # 獲取url的編碼 request.blueprint # 請求屬於的藍圖 # 和路由相關的屬性 print(request.url_root) print(request.url) print(request.url_rule) print(request.host_url) print(request.base_url) print(request.path) # 路由路徑,如/time print(request.full_path) # 全路徑,包括參數 print(request.script_root) print(request.host) # 服務器的ip print(request.access_route) # 全部轉發的ip地址列表 print(request.remote_addr) # 客戶端遠程地址 # 結果 http://192.168.1.112:8000/ http://192.168.1.112:8000/time/time?a=1 /time/time http://192.168.1.112:8000/ http://192.168.1.112:8000/time/time # 獲取請求數據 print(request.is_json) # 判斷請求數據是不是json格式 print(request.get_json()) # 獲取json數據 print(request.args) # 獲取url中的參數做爲字典返回,沒有返回空對象 print(request.form) # 獲取表單數據 print(request.values) # 同時獲取表單數據和url參數 print(request.data) # 沒有被其餘格式解析成功的數據 print(request.files) # 獲取上傳的文件 print(request.cookies) # 獲取cookie print(request.headers) # 獲取頭部信息
session
session代理的是請求上下文RequestContext對象的session屬性,其是在請求上下文被推送到棧的時候建立的session對象,相似一個字典的容器。每次請求建立的session實例都是新的,隨着請求上下文被銷燬而銷燬。
關於flask的session實現機制和運用參考: flask基礎之session機制詳解
應用上下文AppContext
應用上下文對象AppContext會在必要時被建立和銷燬,它不會在線程間移動,而且也不會在不一樣的請求之間共享;所以它能夠做爲在一次請求中臨時存放數據的地方,其主要管理本次請求的當前應用app對象和臨時全局g對象。
current_app = LocalProxy(_find_app) g = LocalProxy(partial(_lookup_app_object, 'g'))
AppContext分析
flask的應用上下文能夠主動建立,在不須要發生http請求的狀況下;當請求上下文被推送到棧後,該請求的應用上下文會跟着建立加入棧中。
class AppContext(object): def __init__(self, app): self.app = app self.url_adapter = app.create_url_adapter(None) self.g = app.app_ctx_globals_class() # app的全局變量
current_app
current_app代理的就是當前的應用,咱們能夠在業務處理的任什麼時候候經過current_app獲取應用app的任何屬性,之因此要這樣作是爲了不app對象被處處顯性傳遞形成循環導入的錯誤。current_app存在於應用上下文活躍期間,會在請求處理完成後,隨着應用上下文銷燬而銷燬
from flask import current_app app = Flask(__name__) with app.app_context(): current_app.url_map
current_app必須在應用上下文被建立而且被推送後才能使用。
g
g通常的用法是在請求期間管理資源,其指向的是當前應用的app_ctx_globals_class屬性,是一個_AppCtxGlobals對象;g對象是隨着應用上下文生存或死亡。
class _AppCtxGlobals(object): # 從g中獲取數據 def get(self, name, default=None): pass # 獲取數據而且彈出 def pop(self, name, default=_sentinel): pass # 在g中添加鍵值對,若是存在則忽略 def setdefault(self, name, default=None): pass
咱們能夠將g對象看作dict的數據結構,它支持g.ab方式獲取值和賦值。
with app.app_context(): g.ab = 'name' # 將{‘ab’:'name'}鍵值對添加到g中 x = g.ab # 獲取ab的值,若是沒有會報錯,因此推薦使用g.get('ab')方法
總結
-
請求上下文面向開發者使用的對象主要是request和session;
-
應用上下文面向開發者使用的對象主要是current_app和g;
-
一次請求期間,請求上下文建立後會建立對應的本次請求的應用上下文;
-
請求上下文通常不能夠單獨存在,由於建立請求上下文須要請求數據做爲參數;可是應用上下文能夠單獨存在而且能夠手動推送;