1. 程式人生 > >flask基礎之AppContext應用上下文和RequestContext請求上下文(六)

flask基礎之AppContext應用上下文和RequestContext請求上下文(六)

路由 init one 格式 周期 coo 需要 app req

前言

應用上下文和請求上下文存在的目的,官方文檔講的很清楚,可參考:

http://www.pythondoc.com/flask/appcontext.html

應用上下文對象在沒有請求的時候是可以單獨存在的,但是請求上下文對象只有在收到請求後才會被創建。請求處理和應用上下文和請求上下文的關系是:

接收請求--》創建請求上下文--》請求上下文入棧--》創建該請求的應用上下文--》應用上下文入棧--》處理邏輯--》請求上下文出棧--》應用上下文出棧

系列文章

  • flask基礎之安裝和使用入門(一)

  • flask基礎之jijia2模板使用基礎(二)

  • flask基礎之jijia2模板語言進階(三)

  • flask基礎之app初始化(四)

  • flask基礎之請求處理核心機制(五)

請求上下文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;

  • 一次請求期間,請求上下文創建後會創建對應的本次請求的應用上下文;

  • 請求上下文一般不可以單獨存在,因為創建請求上下文需要請求數據作為參數;但是應用上下文可以單獨存在並且可以手動推送;

參考

  • https://dormousehole.readthedocs.io/en/latest/appcontext.html#id3

flask基礎之AppContext應用上下文和RequestContext請求上下文(六)