從請求到響應(yīng)過程中django都做了哪些處理
前言
最近面試的時候,被面試官問道一個問題,就是 request.user 里面的 user 是怎樣得到的,這個問題當時沒有回答上來,可以說是非常的尷尬,所以趕快查了一些資料,看了一些源碼,特地來總結(jié)一下這個問題。
要想回答為什么可以直接通過 request.user 得到請求的用戶,應(yīng)該先來看看請求被處理以及如何返回響應(yīng)的流程。今天先總結(jié)一下 django 從請求到響應(yīng)都進行了哪些過程。
WSGI
當客戶端發(fā)送一次請求后,最先處理請求的實際上是 web 服務(wù)器就是我們經(jīng)常說的 nginx、Apache 這類的 web 服務(wù)器,而 WSGI 的作用就是把 web 服務(wù)器和 web 框架 (Django) 連接起來。WSGI 被分為了兩個部分:服務(wù)端和應(yīng)用端。為了處理一個 WSGI 的響應(yīng),服務(wù)端執(zhí)行應(yīng)用程序并向應(yīng)用端提供一個回調(diào)函數(shù),應(yīng)用端處理請求并使用提供的回調(diào)將響應(yīng)返回給服務(wù)端。
本質(zhì)上來講,我覺得 WSGI 就是 web 服務(wù)器和 django 應(yīng)用之間的一個聯(lián)系人。
數(shù)據(jù)流
當用戶向你的應(yīng)用發(fā)送一個請求的時候,一個 WSGI handler 將會被初始化,它會完成以下工作:
- 導(dǎo)入 settings.py 和 django 的異常類
- 使用 load_middleware 方法加載 settings.py 中 MIDDLEWARE_CLASSES 或者 MIDDLEWARES 元組中所用的 middleware classes.
- 創(chuàng)建四個列表 (_request_middleware,_view_middleware, _response_middleware, _exception_middleware),里面分別包含處理 request,view,response 和 exception 的方法。
- WSGI Handler 將實例化一個 django.http.HTTPRequest 對象的子類,django.core.handlers.wsgi.WSGIRequest.
- 循環(huán)遍歷處理 request 的方法 (_request_middleware 列表),并按照順序調(diào)用他們
- 解析請求的 url
- 循環(huán)遍歷每個處理 view 的方法 (_view_middleware 列表)
- 如果找的到的話,就調(diào)用視圖函數(shù)
- 處理任何異常的方法 (_exception_middleware 列表)
- 循環(huán)遍歷每個處理響應(yīng)的方法 (_response_middleware 列表),(從內(nèi)向外,與請求中間件的順序相反)
- 最后得到一個響應(yīng),并調(diào)用 web server 提供的回調(diào)函數(shù)
中間件
中間件被用在了 django 的許多關(guān)鍵功能中:例如,使用 CSRF 中間鍵來防止跨站請求偽造攻擊。它們也被用來處理會話數(shù)據(jù),身份認證和授權(quán)同樣是由中間件來完成的。我們也可以自己編寫中間件來調(diào)整或者(短路)通過應(yīng)用程序的數(shù)據(jù)流。
django 的中間件至少含有以下四個方法中的一個:process_request, process_response, process_view, process_exception。這些方法會被 WSGI handler 收集并按照順序調(diào)用。
process_request
我們可以先來看看 django.contrib.auth.middleware.AuthenticationMiddleware:
def get_user(request): if not hasattr(request, '_cached_user'): request._cached_user = auth.get_user(request) return request._cached_user class AuthenticationMiddleware(MiddlewareMixin): def process_request(self, request): assert hasattr(request, 'session'), ( "The Django authentication middleware requires session middleware " "to be installed. Edit your MIDDLEWARE%s setting to insert " "'django.contrib.sessions.middleware.SessionMiddleware' before " "'django.contrib.auth.middleware.AuthenticationMiddleware'." ) % ("_CLASSES" if settings.MIDDLEWARE is None else "") request.user = SimpleLazyObject(lambda: get_user(request))
這里我們可以發(fā)現(xiàn) request.user 這個屬性是在 AuthenticationMiddleware 中產(chǎn)生的。這個我們稍后再說。
這里我們可以發(fā)現(xiàn),這個中間件只有 process_request,說明它只在 request 這一步處理流入和流出 django 應(yīng)用的數(shù)據(jù)流。這個中間件會首先驗證會話中間件是否被使用,然后通過調(diào)用 get_user 函數(shù)來設(shè)置用戶。當 WSGI 處理程序迭代
process_request 方法列表的時候,它將會構(gòu)建這個最終會被傳遞給視圖函數(shù)的請求對象,并能夠使你引用 request.user。一些中間件沒有 process_request 方法,在這個階段,會被跳過。
process_request 應(yīng)該返回 None 或者 HTTPResponse 對象。當返回 None 時,WSGI handler 會繼續(xù)加載 process_request 里面的方法,但是后一種情況會短路處理過程并進入 process_response 循環(huán)。
解析 url
當所有的 process_request 被調(diào)用完之后,我們就會得到一個將被傳遞給視圖函數(shù)的 request 對象。當這個事件發(fā)生之前,django 必須解析 url 并決定調(diào)用哪一個視圖函數(shù)。這個過程非常簡單,只需要使用正則匹配即可。settings.py 中有一個 ROOT_URLCONF 鍵來指定根 url.py,在這里會包含你所有 app 的 urls.py 文件。如果沒有匹配成功,將會拋出一個異常 django.core.urlresolvers.Resolver404, 這是 django.http.HTTP404 的子類。
process_view
到這一步之后 WSGI handler 知道了調(diào)用哪一個視圖函數(shù),以及傳遞哪些參數(shù)。它會再一次調(diào)用中間件列表里面的方法,這次是_view_middleware 列表。所有 Django 中間件的 process_view 方法將會被這樣聲明:
process_view(request, view_function, view_args, view_kwargs)
和 process_request 一樣,process_view 函數(shù)必須返回 None 或者 HTTPResponse 對象,使得 WSGI handler 繼續(xù)處理視圖或者'短路'處理流程并返回一個響應(yīng)。在 CSRF middleware 中存在一個 process_view 的方法。作用是當 CSRF cookies 出現(xiàn)時,process_view 方法將會返回 None, 視圖函數(shù)將會繼續(xù)的執(zhí)行。如果不是這樣,請求將會被拒絕,處理流程將會被'短路',會生成一個錯誤的信息。
進入視圖函數(shù)
一個視圖函數(shù)需要滿足三個條件:
- 必須是可以調(diào)用的。這可以是基于函數(shù)的視圖或者是 class-based 的視圖(繼承自 View 并且使用 as_view() 方法來使它成為可調(diào)用的。這些方法的調(diào)用依賴 HTTP verb(GET, POST, etc))
- 必須接受一個 HTTPRequest 對象作為第一個位置參數(shù)。這個 HTTPRequest 對象是被所有 process_request 和 process_view 中間件方法處理的結(jié)果。
- 必須返回一個 HTTPResponse 對象,或者拋出一個異常。就是用這個 response 對象來開啟 WSGI handler 的 process_view 循環(huán)。
process_exception
如果視圖函數(shù)拋出一個異常,Handler 將會循環(huán)遍歷_exception_middleware 列表,這些方法按照相反的順序執(zhí)行,從 settings.py 里面列出來的最后一個中間件到第一個。如果一個異常被拋出,處理過程將會被短路,其他的 process_exception 將不會被執(zhí)行。通常我們依賴 Djnago's BaseHandler 提供的異常處理程序,但是我們也可以使用自定義的異常處理中間件。
process_response
在這個階段,我們得到了一個 HTTPResponse 對象,這個對象可能是 process_view 返回的,也可能是視圖函數(shù)返回的?,F(xiàn)在我們將循環(huán)訪問響應(yīng)中間件。這是中間件調(diào)整數(shù)據(jù)的最后的機會。執(zhí)行的順序是從內(nèi)向外執(zhí)行。
以 cache middleware 的 process_response 為例:它依賴于你的 app 里面的不同的狀態(tài)(緩存是否打開或者關(guān)閉,是否在處理一個數(shù)據(jù)流),來決定是否緩存你的響應(yīng)。
注意
django 1.10 和之前版本的區(qū)別:
在舊版本的 MIDDLEWARE_CLASSES 中,就算一個中間件”短路”了執(zhí)行過程,所有的中間件都會調(diào)用它們的 process_response 方法。而在新的 MIDDLEWARES 版本中,只有這個中間件和在它之前執(zhí)行的中間件才會調(diào)用 process_response 方法。
總結(jié)
以上就是 django 在處理一個請求的基本的過程,最后 django 的 WSGI Handler 會創(chuàng)建一個來自 HTTPResponse 的返回值,而且會調(diào)用回調(diào)函數(shù)把數(shù)據(jù)傳遞給 web server, 最后返回給用戶。
以下是兩個關(guān)鍵點:
我們現(xiàn)在知道了視圖函數(shù)是如何和 url 解析器匹配以及什么在調(diào)用它 (WSGI Handler)
有四個關(guān)鍵的地方可以讓你掛鉤到請求 / 響應(yīng)周期:process_request, process_response, process_view, process_exception。請求中間件是從外部向內(nèi)執(zhí)行,最后抵達到視圖函數(shù),然后通過響應(yīng)中間件從內(nèi)向外返回。
參考資料
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
python?request要求接口參數(shù)必須是json數(shù)據(jù)的處理方式
這篇文章主要介紹了python?request要求接口參數(shù)必須是json數(shù)據(jù)的處理方式,Reqeusts支持以form表單形式發(fā)送post請求,只需要將請求的參數(shù)構(gòu)造成一個字典,然后傳給requests.post()的data參數(shù)即可,本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧2022-08-08安裝pyhttpx解決ImportError: DLL load failed錯誤
這篇文章主要為大家介紹了安裝pyhttpx解決ImportError: DLL load failed錯誤,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08Windows下安裝python2和python3多版本教程
這篇文章主要介紹下Windows(我用的Win10)環(huán)境下的python2.x 和 python3.x 的安裝,以及python2.x 與 python3.x 共存時的配置問題。2017-03-03pytorch中的scatter_add_函數(shù)的使用解讀
這篇文章主要介紹了pytorch中的scatter_add_函數(shù)的使用解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06python調(diào)用短信貓控件實現(xiàn)發(fā)短信功能實例
這篇文章主要介紹了python調(diào)用短信貓控件實現(xiàn)發(fā)短信功能實例,需要的朋友可以參考下2014-07-07全面了解Python的getattr(),setattr(),delattr(),hasattr()
下面小編就為大家?guī)硪黄媪私釶ython的getattr(),setattr(),delattr(),hasattr()。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06VSCode搭建Django開發(fā)環(huán)境的圖文步驟
本篇介紹在vscode環(huán)境下搭建Django開發(fā)環(huán)境的詳細步驟,包括Python、Django、VSCode等,以及它們的安裝和配置方法,具有一定的參考價值,感興趣的可以了解一下2023-09-09如何利用python創(chuàng)建、讀取和修改CSV數(shù)據(jù)文件
csv文件與txt文件類似,區(qū)別點就是在csv文件中,字段間使用“,”或“|”隔開,達到類似與表格的效果,下面這篇文章主要給大家介紹了關(guān)于如何利用python創(chuàng)建、讀取和修改CSV數(shù)據(jù)文件的相關(guān)資料,需要的朋友可以參考下2022-05-05ssh批量登錄并執(zhí)行命令的python實現(xiàn)代碼
有個任務(wù)是在這些電腦上執(zhí)行某些命令,者說進行某些操作,比如安裝某些軟件,拷貝某些文件,批量關(guān)機等。如果一臺一臺得手工去操作,費時又費力,如果要進行多個操作就更麻煩啦2012-05-05