Flask的請求鉤子與上下文簡覽

請求鉤子(Hook)

在客戶端和服務器交互的過程當中,有些準備工做或掃尾工做須要處理,好比:在請求開始時,創建數據庫鏈接;在請求結束時,指定數據的交互格式。爲了讓>每一個視圖函數避免編寫重複功能的代碼,Flask提供了通用設施的功能,即請求鉤子。經過請求鉤子,咱們能夠對請求進行預處理(preprocessing)和後處理>(postprocessing)。shell

Flask的請求鉤子經過裝飾器實現,每一個鉤子能夠註冊任意多個處理函數,默認的五種請求鉤子以下:數據庫

鉤子 說明
before_first_request 註冊一個函數,在處理請求前運行
before_request 註冊一個函數,在處理每一個請求前運行
after_request 註冊一個函數,若是有未處理的一場拋出。會在每一個請求結束後運行
teardown_request 註冊一個函數,即便有未處理的異常拋出,會在每一個請求介紹後執行。若是發生異常,會傳入異常對象做爲參數註冊到函數中
after_this_request 在視圖函數內註冊一個函數,在這個請求結束後運行

假如咱們建立了三個視圖函數A、B、C,其中視圖C使用了after_this_request鉤子,那麼當請求A進入後,整個請求處理週期的請求處理函數調用流程如圖:flask

AEdgN4.png

上下文

什麼是上下文?上下文至關於一個容器,它保存了程序運行過程當中的一些信息,它是當前環境的一個快照(snapshot)。 Flask中有兩種上下文,程序上下文(application context)和請求上下文(request context)。 程序上下文中包含了程序運行所必須的信息;請求上下文裏包含了請求的各類信息,好比請求的URL、HTTP方法等服務器

上下文全局變量

咱們知道,Flask將請求報文封裝在request對象中。按照通常的思路,若是咱們要在視圖函數中使用它,就得把它做爲參數傳入視圖函數,就像咱們接收URL變量同樣。但這樣就會致使大量的重複,並且增長了的程序的負擔。 不通常的是,咱們能夠從Flask導入一個全局的request變量,在視圖函數中直接調用request的屬性獲取數據。這是爲何?由於Flask會在每一個請求產生後後自動激活當前請求的上下文,激活請求上下文後,request被臨時設置爲全局可訪問。在每一個請求結束後,Flask就會銷燬對應的請求上下文。session

Flask提供的四個上下文全局變量以下: |變量名|上下文類別|說明| |:--:|:--:|:--| |current_app|程序上下文|指向處理請求的當前程序實例| |g|程序上下文|替代Python的全局變量用法,確保僅在當前請求可用,用於存儲全局數據,每次請求都會重設| |request|請求上下文|封裝客戶端發出的請求報文數據| |session|請求上下文|用於記住請求之間的數據,經過簽名的Cookie實現|app

  • 不一樣的視圖函數中,request對象都表示和視圖函數對應的請求,也就是當前請求
  • 程序存在多個程序實例的狀況,使用current_app可獲取對應的實例

上下文的激活

請求進入時,Flask會自動激活請求上下文,此時程序上下文也被自動激活。請求處理完畢後,請求上下文和程序上下文也會自動銷燬。二者具備相同的生命週期。函數

  • Flask自動激活上下文的狀況:post

    • 使用flask run命令啓動程序時
    • 使用舊的app.run()方法啓動程序時
    • 執行使用@app.cli.command()裝飾器註冊的flask命令時
    • 使用flask shell命令啓動Python Shell時
  • 手動激活的方法:this

    • 使用with語句,程序上下文對象可經過app.app_context()獲取
    • 使用push()方法激活程序上下文
    • 請求上下文能夠經過test_request_context()方法臨時建立
>>> from app import app
>>> from flask import current_app
>>> with app.app_context():
    ... current_app.name
'app'
>>> from app import app
>>> from flask import current_app
>>> app_ctx = app.app_context()
>>> app_ctx.push()
>>> current_app.name
'app'
>>> app_ctx.pop()
>>> from app import app
>>> from flask import request
>>> with app.test_request_context('/hello'):
...     request.method
'GET'

參考:https://book.douban.com/subject/30310340/spa

相關文章
相關標籤/搜索