一、web請求生命周期分析
1、概述
web請求是基於http協議的,而http協議是基於請求/響應的模式,即一個請求對應一個響應,那么一個web請求(或者說http請求)的生命周期就是指從發起一個web請求到得到web響應的過程
- web請求的發起:一般是指在瀏覽器中輸入一個url地址,但是並不僅限於此,譬如我們在網頁中點擊一個url鏈接或者javascript腳本中執行一個url跳轉(包括普通的和ajax方式的)等
- web響應的獲取:一般是顯示在瀏覽器中的一個頁面,但是也並不僅限於此,有些是后台數據的獲取,譬如javascript訪問的json數據、圖片、文件等
2、相關知識點
1、網絡核心結構
計算機的網絡核心結構,就是TCP/IP五層網絡模型(OSI七層網絡模型將應用層拆分為三層了),如下圖:
-
發送請求的過程是從最頂層(應用層)出發,每一層負責封裝屬於自己的信息到請求中,最后將一整個請求發送給對方。
-
接收請求的過程是從最底層(網絡接口層)開始,每一層的協議負責解析屬於自己的東西,比如網絡層(IP)處理ip信息,傳輸層(TCP)處理點對點的端口,應用層(HTTP)處理Request或Response的Line\Header\Body。
2、TCP協議
TCP(Transmission Control Protocol,傳輸控制協議)是一種面向連接(連接導向)的、可靠的基於字節流的傳輸層通信協議。TCP將用戶數據打包成報文段,它發送后啟動一個定時器,另一端收到的數據進行確認、對失序的數據重新排序、丟棄重復數據。
頭格式如下(單位 bit):
- Source Port(源端口號):數據發起者的端口號,16bit。
- Destination Port(目的端口號):數據接收者的端口號,16bit。
- Sequence Number(順序號碼,Seq):用於在數據通信中解決網絡包亂序(reordering)問題,以保證應用層接收到的數據不會因為網絡上的傳輸問題而亂序(TCP會用這個順序號碼來拼接數據),32bit。
- Acknowledgment Number(確認號碼,ack):是數據接收方期望收到發送方在下一個報文段的順序號碼(Seq),因此確認號碼應當是上次已成功收到順序號碼(Seq)加1,32bit。
- Offset(TCP報文頭長度):用於存儲報文頭中有多少個32bit(上圖的一行),存儲長度為4bit,最大可表示(23+22+2^1+1)32bit=60bytes的報文頭。最小取值5,532bit=20bytes。
- Reserved(保留):6bit, 均為0
- TCP Flags(TCP標識位)每個長度均為1bit
CWR:壓縮,TCP Flags值0x80。
ECE:擁塞,0x40。
URG:緊急,0x20。當URG=1時,表示報文段中有緊急數據,應盡快傳送。
ACK:確認,0x10。當ACK = 1時,代表這是一個確認的TCP包,取值0則不是確認包。
PSH:推送,0x08。當發送端PSH=1時,接收端盡快的交付給應用進程。
RST:復位,0x04。當RST=1時,表明TCP連接中出現嚴重差錯,必須釋放連接,再重新建立連接。
SYN:同步,0x02。在建立連接時用來同步序號。SYN=1, ACK=0表示一個連接請求報文段。SYN=1,ACK=1表示同意建立連接。
FIN:終止,0x01。當FIN=1時,表明此報文段的發送端的數據已經發送完畢,並要求釋放傳輸連接。
- 窗口:用來控制對方發送的數據量,通知發放已確定的發送窗口上限。
- 檢驗和:該字段檢驗的范圍包括頭部和數據這兩部分。由發端計算和存儲,並由收端進行驗證
- 緊急指針:緊急指針在URG=1時才有效,它指出本報文段中的緊急數據的字節數。
- TCP選項:長度可變,最長可達40字節
三次握手(建立連接的過程,只能客戶端發起):
- 客戶端主動發送SYN包到服務器,並進入SYN_SEND狀態,等待服務器確認
- 服務器收到SYN包並確認,發送SYN+ACK到客戶端,服務器進入SYN_RECV狀態
- 客戶端收到SYN+ACK包,發送ACK確認連接,發送完畢后客戶端和服務端進入ESTABLISHED狀態,完成三次握手
完成三次握手之后,TCP才可以開始進行真正的數據傳輸
四次揮手(斷開連接的過程,可以是客戶端發起,也可以是服務器端發起,下面以客戶端演示):
- 主機A主動發送FIN包,等待主機B確認
- 主機B收到FIN包並確認,發送ACK包到主機A
- 主機B發送FIN包到主機A,並等待主機A確認
- 主機A收到FIN包並確認,發送ACK包到主機B,並且丟棄連接,主機B收到ACK包后,丟棄連接
3、http協議
超文本傳輸協議(HTTP,HyperText Transfer Protocol)是互聯網上應用最為廣泛的一種網絡協議,所有的WWW文件都必須遵守這個標准,屬於TCP/IP協議的應用層協議。
HTTP是一個屬於應用層的面向對象的協議,由於其簡捷、快速的方式,適用於分布式超媒體信息系統。它於1990年提出,經過幾年的使用與發展,得到不斷地完善和擴展。
-
1991年推出HTTP/0.9
-
1996年推出HTTP/1.0
-
1999年推出HTTP/1.1
-
2015年推出HTTP/2
目前使用最廣泛的還是HTTP/1.1版本
URL(統一資源定位符):是一種特殊的URI(統一資源標識符),包含了用於查找某個資源的足夠的信息,格式如下:
http://host[:port][abs_path]?arg1=value1&arg2=value2
https://host[:port][abs_path]?arg1=value1&arg2=value2
說明如下:
- http或https表示要通過哪個協議來定位網絡資源;
- host表示合法的Internet主機域名或者IP地址;
- port指定一個端口號,為空則使用缺省端口(http是80,https是443);
- abs_path指定請求資源的路徑
- ? 之后的內容是請求參數,用於傳遞數據給服務器
http請求:由三部分組成,分別是:請求行、請求頭、請求體
示例(百度登錄請求):
POST /v2/api/?login HTTP/1.1
Host: passport.baidu.com
Connection: keep-alive
Content-Length: 2952
Cache-Control: max-age=0
Origin: https://www.baidu.com
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://www.baidu.com/?tn=93882546_hao_pg
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: BAIDUID=311E2F4D0EBD022DEF679D1669ABDA5E:FG=1; BIDUPSID=311E2F4D0EBD022DEF679D1669ABDA5E; PSTM=1518263013; BDRCVFR[MR02hGxyoCt]=n4QtfkUpMj3XZN4pgPWQhPEUf; H_PS_PSSID=; HOSUPPORT=1; FP_UID=46c02caec5901194ab8efae92be3a433; UBI=fi_PncwhpxZ%7ETaKAT9p784t3RaHLuAic2iv9oBYbhONamuLF2uMuBXPcd5myIbqV4zYbuJyfGkNp-qoLA3f
staticpage=https%3A%2F%2Fwww.baidu.com%2Fcache%2Fuser%2Fhtml%2Fv3Jump.html&charset=UTF-8&token=dae86b918bb5266fd7d94132271a6b68&tpl=mn&subpro=&apiver=v3&tt=1518266296874&codestring=jxG4807c1f71181c16d025115c14301247f884a430735047e38&safeflg=0&u=https%3A%2F%2Fwww.baidu.com%2F%3Ftn%3D93882546_hao_pg&isPhone=&detect=1&gid=52342BA-C1AC-4062-BBD0-8C67681E0D24&quick_user=0&logintype=dialogLogin&logLoginType=pc_loginDialog&idc=&loginmerge=true&splogin=rate&username=mumuloveshine&password=KQueIucNzF0fy78bKHTPQxYb0yrvcQ341y3zq0I86foUW9e%2BjGaTwwlgd2MSmMlWCPqJwZbXoim7wqbFuySCjDtz2gFWdrcDiL9I1b2rUWLN5b7vUHBItKXDGcS7g%2FUKzrm%2FaJcQn13f8eRJfUVw4RjczfLnnegXb0ZpdSmcnkE%3D&verifycode=%E5%A5%B3%E5%AD%A9&mem_pass=on&rsakey=zYBPxF7R8Ucf8O5JkF3HPVBCnaY0hRMD&crypttype=12&ppui_logintime=20572&countrycode=&fp_uid=46c02caec5901194ab8efae92be3a433&fp_info=46c02caec5901194ab8efae92be3a433002%7E%7E%7E-r--5LhFGVwgn%7E5_u--4vhxn7nVCBTkCeT_hhxn7nVCBTkneT_V-kTsP-kTsH--sz-k-sQh0I-LXKSCbjKAe6Kn%7EcKCeLjA7YxLX8%7EAOn%7EA7qkC%7Eqjn7ojUOI%7EC74zA7q%7EnmOjUwLaCe6kC7okA7wxLVKSHl2DLVc_%7Eu-qMu-qOu-qtu-ssh0VkcX1aFX2tpXGopVChpJGgFoHWLlhyFZ82pl2tpXG%7EGVwOHEH9plGDMJCwpBCwLVHWLBsD4Ewt4JCPpVH5Gohn4EGOMJfWFlwOHJ1epVjzHJjz3tyVHEr%7EMJ1gAeogCZIj3eoKC%7Eq9Dh0lwHXGl4EGDFbjepVhiFJj94V2zMJ1gLkI%7ECmreCmYOA7q%7E4%7EczA7nIC7nV4%7E6InlHtnlGtHJHlC7FwHmywn%7ECtnmsyneFenJrl4ewy4lClHl2yAXnInXoVUlrt4eHy4e4Kn%7Eye4ecVH72l4JHwCV2wHmCOnlnVHmYln%7E2l4l5hAJcanV4%7En%7ECOn%7EFlHmohn76InXHeHecaAX2xAJ2tCmOkHJ2wCmHyHe5aHmGenXYyH7Cw4%7ET84J5zCmyeC7wOn7TaCerlH7yy47chHX4V4%7E68CVnan7L8CeyeCkjeCeLzn%7E4jH7CwCecjCloKCXre4estn%7EHOnmOhH7COAXCeHX4hnVoaAJYlCJYl4%7EOKnm5KHmTk47TjC7CtA74VUlYwHl2hpbYx4V1ipEGgMJCyFXwWpBCxCXCe4V2w4%7EYlAm5jC%7ECeCl48AXo%7ECmst4lchHJnICeweH72O4%7EYt4Vnhn%7E6KC%7Enanl68nmqhHenanmyOAJojCkjw4eFeCeTaCXo8nX6zCVreAmL%7EnV4knJnVHJYl476hHXnkC%7EOj47COAJGOC7oaA7oz4lchCVClH7TanXGyHm5zAu-sTu-syu-sxu-sW--5KhFRlTi6zI_FhxFJjPpl1kpT__-u-sG--qIu-qYu-qiu-qcu-qau-qNhV37ogCm58Cm6IAm5%7EAmLzC%7E5zC6__&loginversion=v4&dv=tk0.57134848608022451518266276367%40vAt0nmsmad9kr%7E9koc9koy9krcsmacs4ogs4rd9krjsmac24Sgs4Hz9krzs1ac2%7Eogs4Sa9krds1ayskHgsF6%7E9k0j21ay2%7ESgsF5d9ksasS__vt0lBsF0d9kqgJrtBGjuh4JeT6t2oE%7EraEjej5-Jy4WtVCAa-24rj9ksasMaysF3gsmc6o6dp63t2Ejeo6jhTs4hTEzJ%7ECEuBHKjL9kHlsFqgs%7EqyTk0yBAac9tGh43QAo6jTEjh46tvcsteTQE2L53dIOK6g2%7E0zsAa%7Eskuv9kqgJrtBGjuh4JeT6t2oE%7EraEjej5-Jy4WtVCAalB43%7E9ksasMad9kqgJrtBGjuh4JeT6t2oE%7EraEjej5-Jy4WtVCAadB4s-9ksasMa_ut0yB2F6z9kocsAay24o%7E9ma%7Eskuv2%7Eqd9kSg2kq%7EsAags%7EqyTk6-Bmay24Sgs40z2kHgJrtBGjuh4JeT6t2oE%7EraEje-CEuXCMLkO-GL9ksasMaz24rgsFSd9krjBksl9tGh43QAo6jTEjh46tvcsteTQWJyPKCdo-e3C6LVCya%7Eskuv245c9k0%7EsmacB43a2mc6o6dp63t2Ejeo6jhTs4hTEzhI5z2zOzu39ksasMa_BmmC%7Emx37ZTPhxthsAay9kHbztqQnga9F6zs4sbBkol2Fqlsk0y2k6c24rlsFH-sF5-s%7EHzht0LmPpGb5psR9yezQz5ZHWtXCp6ZH-eV9%7EebOFbds%7ESlsF6b2LeUHKeT5n5gQKd3CKCXOWJ3wtlB4og94olsmacs%7Esl9k6c2yacs%7EH-9k5-Bmacs%7EH-9kr%7E2%7E5g2Fra&traceid=54784D01&callback=parent.bd__pcbs__t0v21n
請求method必須為大寫,現在一般只使用GET和POST,所有方法的說明如下:
http響應:由三部分組成,響應行、響應頭和響應體
示例(百度登錄返回):
HTTP/1.1 200 OK
Access-Control-Expose-Headers: Trace-ID
Cache-Control: public
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html
Date: Sat, 10 Feb 2018 12:38:17 GMT
Expires: 0
Last-Modified: Sat, 10 Feb 2018 12:38:16 12FebGMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Pragma: public
Server: Apache
Strict-Transport-Security: max-age=31536000
Trace-Id: 54784D01
Tracecode: 22969190170312486410021020
Tracecode: 22969190170969169930021020
Vary: Accept-Encoding
Transfer-Encoding: chunked
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<script type="text/javascript">
var href = decodeURIComponent("https:\/\/www.baidu.com\/cache\/user\/html\/v3Jump.html")+"?"
var accounts = '&accounts='
href += "err_no=7&callback=parent.bd__pcbs__t0v21n&codeString=jxG9007e2f71134c1fc023315e99801277b88a24406f10431e8&userName=mumuloveshine&phoneNumber=&mail=&hao123Param=&u=https://www.baidu.com/%3Ftn%3D93882546_hao_pg&tpl=mn&secstate=&gotourl=&authtoken=&loginproxy=&resetpwd=0&vcodetype=ae20DiYV\/qLGUUeTvt6K91W\/neFrpV1ec8WRrh0h9nSGenOd1efhUH8uDb8AFNyOeVu8G9EJLOnD1f97a3jzAj1o7zbXVVlMs3nq&lstr=<oken=&bckv=&bcsync=&bcchecksum=&code=&bdToken=&realnameswitch=&setpwdswitch=&bctime=&bdstoken=&authsid=&jumpset=&appealurl=&realnameverifyemail=0&traceid=54784D01&realnameauthsid="+accounts;
if(window.location){
window.location.replace(href);
}else{
document.location.replace(href);
}
</script>
</body>
</html>
4、服務器相關協議
web協議,是web服務器和web請求處理程序之間傳輸數據的一種標准協議,發展史為:
CGI -> FCGI -> WSGI
說明如下:
-
CGI:通用網關接口(Common Gateway Interface/CGI),最早的web協議
-
FCGI:Fast CGI,在CGI基礎上,提高了服務性能
-
WSGI:Web Server Gateway Interface,專用於python程序,在CGI的基礎上改進的協議
-
uwsgi:uWSGI服務程序自有的協議(不是一個web協議),常用於在uWSGI服務器與其他網絡服務器程序的數據通信,與WSGI沒有關系。
uWSGI是一個Web服務器程序,它實現了WSGI、uwsgi、http等協議。uWSGI起何作用,取決於架構方式:
- 如果架構是Nginx+uWSGI+Django, 那么uWSGI是一個中間件
- 如果架構是uWSGI+Django,那么uWSGI是一個web服務器
5、nginx服務器
nginx是一個高性能的HTTP和反向代理服務器。
什么是正向代理、反向代理?
- 正向代理,例如平時我們使用的加速器、FQ等代理就是正向代理,客戶機請求代理服務器,代理服務器轉發請求到對應的目標服務器
- 反向代理,部署在Web服務器上,代理所有外部網絡對內部網絡的訪問。瀏覽器訪問服務器,必須經過這個代理,是被動的。
正向代理的主動方是客戶端,反向代理的主動方是Web服務器。
反向代理的作用:
- 安全,客戶端對Web服務器的訪問需要先經過反向代理服務器。這樣可以防止外部程序對Web服務器的直接攻擊。
- 負載均衡,反向代理服務器可以根據Web服務器的負載情況,動態地把HTTP請求交給不同的Web服務器來處理,前提是要有多個Web服務器。
- 提升Web服務器的IO性能。一個HTTP請求的數據,從客戶端傳輸給服務器,是需要時間的,例如N秒,如果直接傳給Web服務器,Web服務器就需要讓一個進程阻塞N秒,來接收IO,這樣會降低Web服務器的性能。如果使用反向代理服務器,先讓反向代理服務器接收完整個HTTP請求,再把請求發給Web服務器,就能提升Web服務器的性能。還有一些靜態文件的請求,可以直接交給反向代理來處理,不需要經過Web服務器。
3、生命周期分析
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,性能最好
PS:
- 有些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的process_request
中間件的process_request方法列表對request對象進行處理
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',
]
一般情況下這些中間件都會啟用,如果需要增加自定義的中間件(該中間件類必須繼承MiddlewareMixin),一般是添加在系統的中間件之下,如:
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',
# 自定義中間層
'my_app.middleware.MyMiddleware',
]
中間件中主要有以下方法(一個中間件類最少需要實現下列方法中的一個):
-
process_request:處理請求對象
參數:request
返回:
- response:調用process_response列表處理
- None:調用下一個中間件的process_request處理
-
process_response:處理響應對象
參數:request, response
返回:
- response:調用上一個中間件的process_response處理
-
process_view:視圖預處理,在視圖函數處理之前調用
參數:request,view_func,view_args,view_kwargs
view_func:url路由匹配到的視圖函數
view_args:視圖函數的可變參數
view_kwargs:視圖函數的可變關鍵字參數
返回:
- response:調用process_response處理
- None:調用下一個中間件的process_view處理
-
process_exception:在視圖函數或中間件處理過程拋出異常時調用
參數:request,exception
exception:是處理過程中拋出的異常對象
返回:
- response:之后的process_exception都不會觸發,而是調用process_response處理
- None:調用上一個中間件的process_exception處理
-
process_template_response:在視圖函數完成操作后調用,默認不執行,除非視圖函數返回的response中有render方法
參數:request,response
response:不是HttpReponse,而是SimpleTemplateResponse對象,具有render方法
返回:
-
response:SimpleTemplateResponse對象,調用上一個中間件的process_template_response處理,最后一個process_template_response處理完成后,會自動調用 response對象中的render方法,得到一個HttpResponse對象,進行返回,再調用process_response操作
中間件方法的執行時有順序的,process_request與process_view是按照順序去執行的,而process_response、process_exception和process_template_response是反序的 :
-
9、URLConf路由匹配
通過urls.py文件中的 urlpatterns 配置找到對應的 視圖函數或者視圖類的方法,如果沒有找到匹配的方法,那么就會觸發異常,由中間件的process_exception 進行處理
10、middleware的process_view
調用中間件的 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類中
至此,django編程的處理部分完畢
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請求的生命周期結束。