Django請求生命周期分析
1.客戶端發送請求
- 在瀏覽器輸入url地址,例如
www.baidu.com
,瀏覽器會自動補全協議(http),變為http://www.baidu.com
,現在部分網站都實現了HSTS
機制,服務器自動從http
協議重定向到https
協議 - 在網頁中點擊超鏈接或
javascript
腳本進行url跳轉,僅設置href
='絕對路徑',瀏覽器會自動使用當前url的協議、host和port,例如在https://tieba.baidu.com/index.html
網頁中,點擊一個超鏈接/f?kw=chinajoy
,會自動訪問https://tieba.baidu.com/f?kw=chinajoy
2. 路由轉發
- IP查找:因特網內每個公有IP都是唯一的,域名相當於IP的別名,因為我們無法去記住一大堆無意義的IP地址,但如果用一堆有意義的字母組成,大家就能快速訪問對應網站
- DNS解析:通過域名去查找IP,先從本地緩存查找,其中本地的
hosts
文件也綁定了對應IP,若在本機中無法查到,那么就會去請求本地區域的域名服務器(通常是對應的網絡運營商如電信),這個通過網絡設置中的LDNS
去查找,如果還是沒有找到的話,那么就去根域名服務器查找,這里有所有因特網上可訪問的域名和IP對應信息(根域名服務器全球共13台) - 路由轉發:通過網卡、路由器、交換機等設備,實現兩個IP地址之間的通信。用到的主要就是路由轉發技術,根據路由表去轉發報文,還有子網掩碼、IP廣播等等知識點
3.建立連接
通過TCP協議的三次握手建立連接
4.傳輸報文
建立連接后,客戶端會通過TCP
依次、有序的發送一定大小的報文,其中包括了超時重傳、阻塞窗口等等概念,用來保證數據包的完整、有序
- http協議使用的明文傳輸,所有內容都是直接可讀的
- https協議是基於
SSL/TLS
加密,而SSL/TLS
是基於TCP
協議的,也就是http
協議報文包裝成TCP
報文進行的加密,使用https
協議的話,如果本地沒有證書和公鑰,那么會從服務器獲取證書並且進行驗證,流程如下:
5.nginx處理
當前django
框架開發的web項目,主流使用的服務器架構是:nginx+uWSGI+django
nginx
監聽公網IP的某個端口,例如80,接收到請求后,分2種情況處理請求:
- 如果是靜態資源(如javascript、css、圖片等)的請求,那么
nginx
直接獲取到該資源,返回給用戶 - 如果是動態內容的請求,那么
nginx
就將請求轉發到uWSGI
,使用的協議一般都是uwsgi
,性能最好
注意:
- 有些
reqeust
會分多個數據包進行發送,nginx
會緩存等待整個request
接收完成才調用uWSGI
- 如果使用的
https
,那么加密、解密都在nginx
中進行處理
6.uWSGI處理
uWSGI
監聽本機IP的某個端口,例如3308,接收到nginx
轉發來的請求后,通過將http
協議轉換為WSGI
協議,和django
程序之間進行通信
7.WSGIHandler處理
當django接受到一個請求時,會初始化一個WSGIHandler
,可以在項目下的wsgi.py
文件進行跟蹤查看:
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_middleware()
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ)
request = self.request_class(environ)
response = self.get_response(request)
......
它接受2個參數:
- environ:是含有服務器端的環境變量
- start_response:可調用對象,返回一個可迭代對象。
這個handler
控制了從請求到響應的整個過程,首先的就是加載django
的settings
配置,然后就是調用django的中間件開始操作
8.middleware中間件處理
django操作中間件,首先會調用process_request
方法,該方法的作用是處理請求對象,它的參數是request
,返回有2種情況
- response:調用process_response列表處理
- None:調用下一個中間件的process_request處理
返回response
之后的中間件及其業務邏輯都不會處理,直接回返回給瀏覽器
返回None
則表示會繼續調用下一個中間件,處理下一個中間件中的邏輯
django項目默認有一些自帶的中間件,如下:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
process_request
會從上往下依次調用MIDDLEWARE
中的中間件,注意:中間件的執行是有順序的,所以我們一般自定義中間件的時候,我們都會將自定義的中間件放到列表最下面
9.URLConf路由匹配
通過urls.py
文件中的 urlpatterns
配置找到對應的 視圖函數或者視圖類的方法,如果沒有找到匹配的方法,那么就會觸發異常,由中間件的process_exception
進行處理
process_exception:在視圖函數或中間件處理過程拋出異常時調用
參數:
- request:請求對象
- exception:是處理過程中拋出的異常對象
返回:
- response:之后的
process_exception
都不會觸發,而是調用process_response
處理 - None:調用上一個中間件的
process_exception
處理
10.middleware的process_view
我們通過路由調用視圖之前,會調用中間件的process_view
方法進行預處理
process_view:視圖預處理,在視圖函數處理之前調用
參數:
- view_func:url路由匹配到的視圖函數
- view_args:視圖函數的可變參數
- view_kwargs:視圖函數的可變關鍵字參數
返回:
- response:調用
process_response
處理 - None:調用下一個中間件的
process_view
處理
11.views處理request
調用對應的視圖函數或視圖類的方法處理request
,例如獲取GET
和POST
參數,並且調用特定的模型對象執行數據庫操作,如果沒有數據庫操作,那么就直接跳到我們后續的14步了
12.models處理
視圖方法中,一般情況下都需要調用模型類進行數據操作,一般是通過模型的manager
管理類進行操作的,如:MyModel.objects.get(pk=1)
如果沒有數據操作,那么這一步和下一步就忽略
13.數據庫操作
如果django
通過模型類執行對數據庫的增刪改查,那么此時整個流程就會在對應的數據庫中執行
14.views處理數據
視圖方法獲取到數據后:
- 將數據封裝到一個
context
字典當中,然后調用指定的template.html
,通過模板中的變量、標簽和過濾器等,再結合傳入的數據context
,會觸發中間件的process_template_response
方法,最終渲染成HttpResponse
- 不調用模板,直接返回數據,譬如
JsonResponse
、FileResponse
等 - 執行
redirect
,生成一個重定向的HttpResponse
,觸發中間件的process_response
后,返回到客戶端,結束該web請求的生命周期
15.middleware的process_response
調用中間件的 process_response
方法進行處理,最后一個中間件的process_response
執行完成后,返回到WSGIHandler
類中
16.WSGIHandler處理
WSGIHandler類獲取到response后
- 先處理
response
的響應行和響應頭,然后調用start_response
返回http協議的 響應行和響應頭 到uWSGI,這個start_response
只能調用一次 - 第一步處理完成后,如果是文件需要對
response
進行,否則就直接將response
作為http協議的body部分返回給uWSGI
17.uWSGI處理
uWSGI接收到django程序的返回后,將所有內容包裝成http協議的內容后,通過uwsgi
協議返回給nginx
服務器處理
18.nginx處理
nginx獲取到uWSGI的返回后,將response通過TCP協議返回給客戶端
19.客戶端接收響應
客戶端接收到服務器的響應后,做對應的操作,例如:顯示在瀏覽器中,或是javascript
的處理等至此,整個web請求的生命周期結束。