一次請求到響應的整個流程


一次請求到響應的整個流程

As we all know,所有的Web應用,其本質上其實就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
#coding:utf-8
    
import  socket
    
def  handle_request(client):
     buf  =  client.recv( 1024 )
     client.send( "HTTP/1.1 200 OK\r\n\r\n" )
     client.send( "Hello, Seven" )
    
def  main():
     sock  =  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     sock.bind(( 'localhost' , 8000 ))
     sock.listen( 5 )
    
     while  True :
         connection, address  =  sock.accept()
         handle_request(connection)
         connection.close()
    
if  __name__  = =  '__main__' :
     main()

  上述代碼使用socket實現了其本質,對於所有的python web程序來說,一般會分為兩部分:服務器程序和應用程序。服務器程序負責對socket服務器進行封裝,並在請求到來時,對請求的數據進行整理。應用程序則負責具體的邏輯處理。為了方便應用程序的開發,避免大家重復的造輪子,因此有人發明了相關的工具——Web框架,for example:Django、Flask、web.py  and so on。不同的框架可能采用不同的目錄結構,但是無論如何,開發出的應用程序都要和服務器程序配合,才能為用戶提供服務。以前,如何選擇合適的Web應用程序框架成為困擾Python初學者的一個問題,這是因為,一般而言,Web應用框架的選擇將限制可用的Web服務器的選擇,反之亦然。那時的Python應用程序通常是為CGI,FastCGI,mod_python中的一個而設計,甚至是為特定Web服務器的自定義的API接口而設計的。

  PythonWeb服務器網關接口(Python Web Server Gateway Interface,縮寫為WSGI)是Python應用程序或框架和Web服務器之間的一種接口,已經被廣泛接受, 它已基本達成它的可移植性方面的目標。

WSGI 沒有官方的實現, 因為WSGI更像一個協議. 只要遵照這些協議,WSGI應用(Application)都可以在任何服務器(Server)上運行, 反之亦然。
  我們今天要講的django web框架就需要使用wsgi,djano內部並沒有實現socket,而是通過socket實現的。

概述:

  Django的請求到響應的流程,簡單的來說就是利用wsgi,當用戶發來一個request進行response,響應前發送request_started信號,經過中間件的process_request,響應完成后會調用中間件的process_response。

1.瀏覽器端用戶用url發來了一個請求

  當django程序啟動時,會根據settings中:

源碼截圖:

(注:這里是project名.wsgi.application,博主創建的project名為s3。)

執行applicaion對應的函數:

源碼截圖:

接下來我們來看get_wsgi_application函數:

源碼截圖:

從上述源碼可看出django每次請求響應都會返回一個WSGIHandler類的實例。

WSGIHandler類源碼截圖:

 

這里,我們需要關注的是:

    load_middleware只有第一次請求會調用,即中間件的加載只會在第一次請求時執行。

    WSGIhandler類中發送了request_started信號。

下來我們首先關注一下他的父類base.BaseHandler類:

base.BaseHandler類源碼截圖:

 

中間件的完整執行流程圖:

備注:由上圖可看出:

  • 當請求到來時,會首先經過中間件的Process_Request,如果Process_Request有return即當前url沒有通過中間件,則程序直接跳轉到最后一個Process_Response,然后逆序執行所有的Process_Response。
  • 然后程序會進入url,這時程序會檢測用戶有沒有設置process_view,如果有,則接下來先執行process_view,如果process_view有return,則程序直接跳轉到最后一個Process_Response,然后逆序執行所有的Process_Response。
  • 如果上一步沒有process_view,程序會執行views文件中的函數
  • 執行完上一步,程序會檢測有沒有異常出現,如果有,則先執行中間件類對應的process_exception
  • 最后,程序會逆序執行所有的Process_Response。

備注:request_middleware、view_middleware 是順序執行,template_response_middleware、response_middleware、exception_middleware 是逆序執行。

url:

首先程序會根據配置文件中:

源碼截圖:

(同樣這是是project名.urls)

找到urls.py文件

url匹配源碼:

這里直接使用當前url是否屬於LocaleRegexURLResolver這個類。

LocaleRegexURLResolver類:

預編譯:

正則匹配:

我們需要關注的是LocaleRegexURLResolver類的resolve方法:

注:self.url_patterns是所有的正則url,這里對正則url進行循環;new_path是用戶輸入的url,這里pattern.resolve是執行RegexURLPattern類的resolve方法:

由上述源碼可看出RegexURLPattern類的resolve方法即通過regex.search進行具體的匹配操作,其中regex封裝了re模塊。

我們定義的url:

示例代碼:

1
2
3
4
5
6
7
8
9
10
from  django.conf.urls  import  url
from  django.contrib  import  admin
from  APP01  import  views
urlpatterns  =  [
     url(r '^admin/' , admin.site.urls),
     url(r '^articles/(?P<year>[0-9]{4})/$' , views.special_case_2003),
     url(r '^articles/([0-9]{4})/$' , views.year_archive),
     url(r '^articles/([0-9]{4})/([0-9]{2})/$' , views.month_archive),
     url(r '^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$' , views.article_detail),
]

源碼url截圖:

從上述源碼中可看出url方法接收正則表達式和view兩個參數,最終返回一個RegexURLPattern對象,RegexURLPattern類對正則表達式和view做進一步處理

 

由上述源碼可看出,在完成正則匹配后,view會被作為回調函數運行。由此解釋了url是如何與views函數進行綁定的。

  接下來,程序調用views函數,並對模板進行渲染,並返回到view,程序如果沒有異常,執行中間件的Process_Response(詳見上文中間件的執行流程),最終程序發送一個信號 request_finished信號,訂閱這個信號的事件會清空並釋放任何使用中的資源。

   如果您覺得本文對您有參考價值,歡迎幫博主點擊文章下方的推薦,謝謝!


免責聲明!

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



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