Django系列 1:請求的生命周期

p

進(jìn)入本文之前疏咐,首先請大家先看該篇博客吊说,對你開始本文的理解有一定的幫助:

Django系列之啟動入口源碼分析

Django 源碼分析:啟動過程

一個(gè)請求request 經(jīng)過瀏覽器命咐, nginx轉(zhuǎn)發(fā)仍劈,uwsgi服務(wù)器霜幼,再到我們的應(yīng)用服務(wù)器飒房,這一過程我們暫且先跳過去赢织,因?yàn)槲覀円芯康氖且粋€(gè)請求request進(jìn)入到應(yīng)用服務(wù)器后擎鸠, 如何匹配到視圖類的(CBV)的揭鳞,進(jìn)入視圖函數(shù)前干了什么炕贵, 出了視圖函數(shù)干了什么,進(jìn)入之前與出去之后都經(jīng)過哪些中間件野崇,這些是我們著重要研究的地方称开。

1:任何一個(gè)應(yīng)用 application,他必須是可調(diào)用的(callable), 因?yàn)檫@是request的入口。源碼位置在Django中的位置如下所示:

2:所有的request都會進(jìn)入run方法:

進(jìn)入run方法以后乓梨, 就會獲取應(yīng)用的application:

3:前面說過django中的application是一個(gè)可調(diào)用對象鳖轰,那么application對應(yīng)的類就是:django.contrib.staticfiles.handlers:StaticFilesHandler 實(shí)例

最后調(diào)用父類的的方法:django.core.handlers.wsgi:WSGIHandler,至此我們已經(jīng)知道所有的request在django框架中的入口處扶镀。

好了蕴侣, 現(xiàn)在我們已經(jīng)知道每個(gè)請求的入口是WSGIHandler.__call__函數(shù), name在這個(gè)函數(shù)最重要的就是這句代碼?response =self.get_response(request)

那我們現(xiàn)在看看這句代碼的背后都干了什么臭觉,重點(diǎn)在這句:self._middleware_chain(request)昆雀,它在項(xiàng)目啟動后會將所有的中間件形成一個(gè)鏈,在鏈的最開始就是配置中MIDDLEWARE第一個(gè)中間件蝠筑。

在load_middleware方法中忆肾,get_response最初是self._get_response方法(即:最初的handler就是get_response),通過循環(huán)每次handler改變菱肖, 第一次循環(huán)后handler就是MIDDLEWARE最后一個(gè)中間件的實(shí)例客冈,一直到循環(huán)結(jié)束,那么handler就是第一個(gè)中間件的是實(shí)例稳强;

當(dāng)代碼執(zhí)行到:

self._middleware_chain(request)

當(dāng)所有的中間件都執(zhí)行完畢后场仲,最后執(zhí)行WSGIHandler的_get_response方法(如下圖)和悦, 該方法包括了,請求解析(找到正確的視圖類)渠缕,視圖函數(shù)中間件鸽素,從wrapped_callback分派執(zhí)行請求方法(get()、post()亦鳞、........)馍忽,template中間件、exception中間件燕差,最后又會執(zhí)行所有中間件的process_response方法

所以一個(gè)請求到達(dá)應(yīng)用服務(wù)器后的流程就是:

(1):request 找到應(yīng)用服務(wù)器 __call__(self, environ, start_response) 方法遭笋,并執(zhí)行 response = self.get_response(request) 方法。

(2):request 進(jìn)入?self.get_response(request) 方法后徒探,最重要的就是執(zhí)行了該句代碼:response = self._middleware_chain(request)

(3):中間件鏈 self._middleware_chain(request) 具體干了這么幾件事:

? ? ? ? ? ? (a):? 順序執(zhí)行中間件實(shí)例的 process_request 方法瓦呼,如果該方法有返回值?response 實(shí)例, 那么不會執(zhí)行后續(xù)的中間件测暗, 而是逆序執(zhí)行中間件的?process_response 方法央串,最后返回服務(wù)器直至瀏覽器

? ? ? ? ? ? (b):? ?當(dāng)所有的?process_request 方法執(zhí)行完畢后,執(zhí)行?WSGIHandler._get_response(self, request) 方法碗啄,根據(jù)請求的path解析到正確的視圖函數(shù)或視圖類(即該方法的 callback或 wrapped_callback)

? ? ? ? ? ? (c):? ?執(zhí)行所有的模板中間件

? ? ? ? ? ? (b):??執(zhí)行所有的異常中間件

? ? ? ? ? ? (d):? 最后逆序執(zhí)行中間件實(shí)例的? ?process_response 方法质和,該方法必須返回一個(gè)?response 實(shí)例 , 最后相應(yīng)返回給wsgi或uwsgi 這樣發(fā)服務(wù)器,由他們返回瀏覽器等前端

那么整個(gè)請求的過程就是在這些過程中完成的稚字,django框架的核心就是圍繞這些流程逐步拓展饲宿,請求解析、模板與響應(yīng)尉共、異常處理等等褒傅。

最后補(bǔ)充一張圖弃锐,關(guān)于請求穿過中間件的順序:


中間件順序的參考:中間件順序


def? process_request(self, request):? pass

def process_view(self, request, callback, callback_args, callback_kwargs):? pass

def?process_template_response(self, request,?response):? pass

def process_exception(self, request, exception):? pass

def process_response(self, request, response):? pass


(1): 在各個(gè)中間件的 process_request 均沒有異常且返回值是None, 那么下一步再按照中間件的順序依次執(zhí)行各自的 process_view, 如果process_view 返回值均是None, 下一步再按照中間件逆序方向從下往上執(zhí)行process_response? 袄友,直至第一個(gè)中間件的process_response? (如黑線箭頭流程所示)

(2):如果執(zhí)行的某個(gè)中間件的 process_request 返回值是HttpResponse 對象,那么直接執(zhí)行該中間件的?process_response霹菊,再按照中間件的逆序方向從下往上執(zhí)行其它的 process_response?? (如紅線箭頭流程所示)

(3):在各個(gè)中間件的 process_request 均沒有異常且返回值是None, 那么下一步再按照中間件的順序依次執(zhí)行各自的 process_view, 如果在某個(gè)中間件的process_view 返回值是?HttpResponse 對象,那么直接逆序執(zhí)行各個(gè)中間件的?process_response (從下到上)(如藍(lán)線箭頭流程所示)

(4):如果在某個(gè)中間件的 process_request 發(fā)生異常剧蚣,那么會直接該中間件的process_response?(從下到上),然后逆序執(zhí)行其它中間的?process_response? 方法(該中間件的process_response? 不會執(zhí)行)旋廷,直到結(jié)束?(如黑線箭頭流程所示)

(5):如果在某個(gè)中間件的 process_view 發(fā)生異常鸠按,那么會直接該中間件的?process_response??(從下到上),然后逆序執(zhí)行其它中間的??process_response? 方法(該中間件的?process_response? 執(zhí)行)饶碘,直到結(jié)束??(如藍(lán)色線箭頭流程所示)

(6):如果執(zhí)行到視圖函數(shù) view 中發(fā)生異常目尖,?那么會依次執(zhí)行各中間件的?process_exception(從下到上),然后逆序執(zhí)行其它各個(gè)中間的??process_response? 方法扎运,直到結(jié)束??(如紅色線箭頭流程所示)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瑟曲,一起剝皮案震驚了整個(gè)濱河市饮戳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌洞拨,老刑警劉巖扯罐,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異烦衣,居然都是意外死亡歹河,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門花吟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秸歧,“玉大人,你說我怎么就攤上這事示辈×让#” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵矾麻,是天一觀的道長纱耻。 經(jīng)常有香客問我,道長险耀,這世上最難降的妖魔是什么弄喘? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮甩牺,結(jié)果婚禮上蘑志,老公的妹妹穿的比我還像新娘。我一直安慰自己贬派,他們只是感情好急但,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搞乏,像睡著了一般波桩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上请敦,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天镐躲,我揣著相機(jī)與錄音,去河邊找鬼侍筛。 笑死萤皂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的匣椰。 我是一名探鬼主播裆熙,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了入录?” 一聲冷哼從身側(cè)響起齐媒,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纷跛,沒想到半個(gè)月后喻括,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贫奠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年唬血,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唤崭。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拷恨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谢肾,到底是詐尸還是另有隱情腕侄,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布芦疏,位于F島的核電站冕杠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏酸茴。R本人自食惡果不足惜分预,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望薪捍。 院中可真熱鬧笼痹,春花似錦、人聲如沸酪穿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽被济。三九已至救赐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間溉潭,已是汗流浹背净响。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工少欺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喳瓣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓赞别,卻偏偏與公主長得像畏陕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子仿滔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容