12.web請求生命周期分析


一、web請求生命周期分析

1、概述

​ web請求是基於http協議的,而http協議是基於請求/響應的模式,即一個請求對應一個響應,那么一個web請求(或者說http請求)的生命周期就是指從發起一個web請求到得到web響應的過程

  • web請求的發起:一般是指在瀏覽器中輸入一個url地址,但是並不僅限於此,譬如我們在網頁中點擊一個url鏈接或者javascript腳本中執行一個url跳轉(包括普通的和ajax方式的)等
  • web響應的獲取:一般是顯示在瀏覽器中的一個頁面,但是也並不僅限於此,有些是后台數據的獲取,譬如javascript訪問的json數據、圖片、文件等

2、相關知識點

1、網絡核心結構

​ 計算機的網絡核心結構,就是TCP/IP五層網絡模型(OSI七層網絡模型將應用層拆分為三層了),如下圖:

tcp_ip_model

  • 發送請求的過程是從最頂層(應用層)出發,每一層負責封裝屬於自己的信息到請求中,最后將一整個請求發送給對方。

  • 接收請求的過程是從最底層(網絡接口層)開始,每一層的協議負責解析屬於自己的東西,比如網絡層(IP)處理ip信息,傳輸層(TCP)處理點對點的端口,應用層(HTTP)處理Request或Response的Line\Header\Body。

2、TCP協議

​ TCP(Transmission Control Protocol,傳輸控制協議)是一種面向連接(連接導向)的、可靠的基於字節流的傳輸層通信協議。TCP將用戶數據打包成報文段,它發送后啟動一個定時器,另一端收到的數據進行確認、對失序的數據重新排序、丟棄重復數據。

​ 頭格式如下(單位 bit):

tcp_datagram

  1. Source Port(源端口號):數據發起者的端口號,16bit。
  2. Destination Port(目的端口號):數據接收者的端口號,16bit。
  3. Sequence Number(順序號碼,Seq):用於在數據通信中解決網絡包亂序(reordering)問題,以保證應用層接收到的數據不會因為網絡上的傳輸問題而亂序(TCP會用這個順序號碼來拼接數據),32bit。
  4. Acknowledgment Number(確認號碼,ack):是數據接收方期望收到發送方在下一個報文段的順序號碼(Seq),因此確認號碼應當是上次已成功收到順序號碼(Seq)加1,32bit。
  5. Offset(TCP報文頭長度):用於存儲報文頭中有多少個32bit(上圖的一行),存儲長度為4bit,最大可表示(23+22+2^1+1)32bit=60bytes的報文頭。最小取值5,532bit=20bytes。
  6. Reserved(保留):6bit, 均為0
  7. 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時,表明此報文段的發送端的數據已經發送完畢,並要求釋放傳輸連接。

  1. 窗口:用來控制對方發送的數據量,通知發放已確定的發送窗口上限。
  2. 檢驗和:該字段檢驗的范圍包括頭部和數據這兩部分。由發端計算和存儲,並由收端進行驗證
  3. 緊急指針:緊急指針在URG=1時才有效,它指出本報文段中的緊急數據的字節數。
  4. TCP選項:長度可變,最長可達40字節

​ 三次握手(建立連接的過程,只能客戶端發起):

  1. 客戶端主動發送SYN包到服務器,並進入SYN_SEND狀態,等待服務器確認
  2. 服務器收到SYN包並確認,發送SYN+ACK到客戶端,服務器進入SYN_RECV狀態
  3. 客戶端收到SYN+ACK包,發送ACK確認連接,發送完畢后客戶端和服務端進入ESTABLISHED狀態,完成三次握手

​ 完成三次握手之后,TCP才可以開始進行真正的數據傳輸

​ 四次揮手(斷開連接的過程,可以是客戶端發起,也可以是服務器端發起,下面以客戶端演示):

  1. 主機A主動發送FIN包,等待主機B確認
  2. 主機B收到FIN包並確認,發送ACK包到主機A
  3. 主機B發送FIN包到主機A,並等待主機A確認
  4. 主機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=&ltoken=&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和反向代理服務器。

​ 什么是正向代理、反向代理?

  1. 正向代理,例如平時我們使用的加速器、FQ等代理就是正向代理,客戶機請求代理服務器,代理服務器轉發請求到對應的目標服務器
  2. 反向代理,部署在Web服務器上,代理所有外部網絡對內部網絡的訪問。瀏覽器訪問服務器,必須經過這個代理,是被動的。

​ 正向代理的主動方是客戶端,反向代理的主動方是Web服務器。

​ 反向代理的作用:

  1. 安全,客戶端對Web服務器的訪問需要先經過反向代理服務器。這樣可以防止外部程序對Web服務器的直接攻擊。
  2. 負載均衡,反向代理服務器可以根據Web服務器的負載情況,動態地把HTTP請求交給不同的Web服務器來處理,前提是要有多個Web服務器。
  3. 提升Web服務器的IO性能。一個HTTP請求的數據,從客戶端傳輸給服務器,是需要時間的,例如N秒,如果直接傳給Web服務器,Web服務器就需要讓一個進程阻塞N秒,來接收IO,這樣會降低Web服務器的性能。如果使用反向代理服務器,先讓反向代理服務器接收完整個HTTP請求,再把請求發給Web服務器,就能提升Web服務器的性能。還有一些靜態文件的請求,可以直接交給反向代理來處理,不需要經過Web服務器。

3、生命周期分析

1、客戶端發送請求

  1. 在瀏覽器輸入url,譬如www.baidu.com,瀏覽器會自動補全協議(http),變為http://www.baidu.com,現在部分網站都實現了HSTS機制,服務器自動從http協議重定向到https協議
  2. 在網頁中點擊超鏈接或javascript腳本進行url跳轉,僅設置 href=‘絕對路徑’,瀏覽器會自動使用當前url的協議、host和port,譬如在 https://tieba.baidu.com/index.html網頁中,點擊一個超鏈接 /f?kw=chinajoy , 會自動訪問 https://tieba.baidu.com/f?kw=chinajoy

2、路由轉發

  1. IP查找:因特網內每個公有IP都是唯一的,域名相當於IP的別名,因為我們無法去記住一大堆無意義的IP地址,但如果用一堆有意義的字母組成,大家就能快速訪問對應網站
  2. DNS解析:通過域名去查找IP,先從本地緩存查找,其中本地的hosts文件也綁定了對應IP,若在本機中無法查到,那么就會去請求本地區域的域名服務器(通常是對應的網絡運營商如電信),這個通過網絡設置中的LDNS去查找,如果還是沒有找到的話,那么就去根域名服務器查找,這里有所有因特網上可訪問的域名和IP對應信息(根域名服務器全球共13台)
  3. 路由轉發:通過網卡、路由器、交換機等設備,實現兩個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種情況處理請求:

  1. 如果是靜態資源(如javascript、css、圖片等)的請求,那么nginx直接獲取到該資源,返回給用戶
  2. 如果是動態內容的請求,那么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請求的生命周期結束。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM