1. 程式人生 > >Django從請求到返回都經歷了什麼

Django從請求到返回都經歷了什麼

轉自

從runserver說起

ruserver是使用django自己的web server,主要用於開發和除錯中, 部署到線上環境一般使用nginx+uwsgi模式

manage.py 探祕

看一下manager.py的原始碼,你會發現上面的命令其實是通過Django的execute_from_command_line方法執行了內部實現的runserver命令,那麼現在看一下runserver具體做了什麼。。
通過原始碼分析可知, ruserserver主要完成兩件事:

1). 解析引數,並通過django.core.servers.basehttp.get_internal_wsgi_application方法獲取wsgi handler;
2). 根據ip_address和port生成一個WSGIServer物件,接受使用者請求

get_internal_wsgi_application的原始碼如下:

image

通過上面的程式碼我們可以知道,Django會先根據settings中的WSGI_APPLICATION來獲取handler;
在建立project的時候,Django會預設建立一個wsgi.py檔案,而settings中的WSGI_APPLICATION配置也會預設指向這個檔案。看一下這個wsgi.py檔案,其實它也和上面的邏輯一樣,最終呼叫get_wsgi_application實現。

django http請求處理流程

Django和其他Web框架一樣,HTTP的處理流程基本類似:接受request,返回response內容。Django的具體處理流程大致如下:

1. 載入settings.py

在通過django-admin.py建立project的時候,Django會自動生成預設的settings檔案和manager.py等檔案,在建立WSGIServer之前會執行下面的引用:

from django.conf import settings

上面引用在執行時,會讀取os.environ中的DJANGO_SETTINGS_MODULE配置,載入專案配置檔案,生成settings物件。所以,在manager.py檔案中你可以看到,在獲取WSGIServer之前,會先將project的settings路徑加到os路徑中。

2. 建立WSGIServer

不管是使用runserver還是uWSGI執行Django專案,在啟動時都會呼叫django.core.servers.basehttp中的run()方法
建立一個django.core.servers.basehttp.WSGIServer類的例項,之後呼叫其serve_forever()方法啟動HTTP服務。run方法的原始碼如下:

def run(addr, port, wsgi_handler, ipv6=False, threading=False):
    server_address = (addr, port)
    if threading:
        httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})
    else:
        httpd_cls = WSGIServer
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
    if threading:
        # ThreadingMixIn.daemon_threads indicates how threads will behave on an
        # abrupt shutdown; like quitting the server by the user or restarting
        # by the auto-reloader. True means the server will not wait for thread
        # termination before it quits. This will make auto-reloader faster
        # and will prevent the need to kill the server manually if a thread
        # isn't terminating correctly.
        httpd.daemon_threads = True
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()

如上,我們可以看到:在建立WSGIServer例項的時候會指定HTTP請求的Handler,
上述程式碼使用WSGIRequestHandler。當用戶的HTTP請求到達伺服器時,
WSGIServer會建立WSGIRequestHandler例項,使用其handler方法來處理HTTP請求(其實最終是呼叫wsgiref.handlers.BaseHandler中的run方法處理)。
WSGIServer通過set_app方法設定一個可呼叫(callable)的物件作為application,上面提到的handler方法最終會呼叫設定的application處理request,並返回response。

其中,WSGIServer繼承自wsgiref.simple_server.WSGIServer,而WSGIRequestHandler繼承自wsgiref.simple_server.WSGIRequestHandler,wsgiref是Python標準庫給出的WSGI的參考實現。其原始碼可自行到wsgiref參看,這裡不再細說。

3. 處理Request

第二步中說到的application,在Django中一般是django.core.handlers.wsgi.WSGIHandler物件,WSGIHandler繼承自django.core.handlers.base.BaseHandler,這個是Django處理request的核心邏輯,它會建立一個WSGIRequest例項,而WSGIRequest是從http.HttpRequest繼承而來

4. 返回Response

上面提到的BaseHandler中有個get_response方法,該方法會先載入Django專案的ROOT_URLCONF,然後根據url規則找到對應的view方法(類),view邏輯會根據request例項生成並返回具體的response。

在Django返回結果之後,第二步中提到wsgiref.handlers.BaseHandler.run方法會呼叫finish_response結束請求,並將內容返回給使用者

Django處理Request的詳細流程

首先給大家分享兩個網上看到的Django流程圖:

mark
流程圖一

image
流程圖二

上面的兩張流程圖可以大致描述Django處理request的流程,按照流程圖2的標註,可以分為以下幾個步驟:

1. 使用者通過瀏覽器請求一個頁面

2.請求到達Request Middlewares,中介軟體對request做一些預處理或者直接response請求
3.URLConf通過urls.py檔案和請求的URL找到相應的View
4.View Middlewares被訪問,它同樣可以對request做一些處理或者直接返回response
5.呼叫View中的函式
6.View中的方法可以選擇性的通過Models訪問底層的資料
7.所有的Model-to-DB的互動都是通過manager完成的
8.如果需要,Views可以使用一個特殊的Context
9.Context被傳給Template用來生成頁面
    a.Template使用Filters和Tags去渲染輸出
    b.輸出被返回到View
    c.HTTPResponse被髮送到Response Middlewares
    d.任何Response Middlewares都可以豐富response或者返回一個完全不同的response
    e.Response返回到瀏覽器,呈現給使用者

上述流程中最主要的幾個部分分別是:Middleware(中介軟體,包括request, view, exception, response),URLConf(url對映關係),Template(模板系統),下面一一介紹一下。

1. Middleware(中介軟體)

Middleware並不是Django所獨有的東西,在其他的Web框架中也有這種概念。在Django中,Middleware可以滲入處理流程的四個階段:request,view,response和exception,相應的,在每個Middleware類中都有rocess_request,process_view, process_response 和 process_exception這四個方法。你可以定義其中任意一個活多個方法,這取決於你希望該Middleware作用於哪個處理階段。每個方法都可以直接返回response物件。

Middleware是在Django BaseHandler的load_middleware方法執行時載入的,載入之後會建立四個列表作為處理器的例項變數:

_request_middleware:process_request方法的列表

_view_middleware:process_view方法的列表

_response_middleware:process_response方法的列表

_exception_middleware:process_exception方法的列表

Django的中介軟體是在其配置檔案(settings.py)的MIDDLEWARE_CLASSES元組中定義的。在MIDDLEWARE_CLASSES中,中介軟體元件用字串表示:指向中介軟體類名的完整Python路徑。例如

`MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]`

Django專案的安裝並不強制要求任何中介軟體,如果你願意,MIDDLEWARE_CLASSES可以為空。中介軟體出現的順序非常重要:在request和view的處理階段,Django按照MIDDLEWARE_CLASSES中出現的順序來應用中介軟體,而在response和exception異常處理階段,Django則按逆序來呼叫它們。也就是說,Django將MIDDLEWARE_CLASSES視為view函式外層的順序包裝子:在request階段按順序從上到下穿過,而在response則反過來。以下這張圖可以更好地幫助你理解:

image

  1. URLConf(URL對映)
如果處理request的中介軟體都沒有直接返回response,那麼Django會去解析使用者請求的URL。URLconf就是Django所支撐網站的目錄。它的本質是URL模式以及要為該URL模式呼叫的檢視函式之間的對映表。通過這種方式可以告訴Django,對於這個URL呼叫這段程式碼,對於那個URL呼叫那段程式碼。具體的,在Django專案的配置檔案中有ROOT_URLCONF常量,這個常量加上根目錄"/",作為引數來建立django.core.urlresolvers.RegexURLResolver的例項,然後通過它的resolve方法解析使用者請求的URL,找到第一個匹配的view。

有關urlconf的內容,大家可以參考 [理解curlConf]()
  1. Template(模板)
大部分web框架都有自己的Template(模板)系統,Django也是。但是,Django模板不同於Mako模板和jinja2模板,在Django模板不能直接寫Python程式碼,只能通過額外的定義filter和template tag實現。由於本文主要介紹Django流程,模板內容就不過多介紹。

相關推薦

【Python web 開發】django 請求到響應經歷什麼?

  setting中註冊的middleware會將使用者request的資料經過這些middlware中有process_request方法和process_response方法註冊進入。 當用戶的request進入view之前會將這些process_request通通呼叫一遍

django請求返回經歷什麽[轉]

admin indicate reg 幫助 頁面 prev manager setting roc 原文地址:http://projectsedu.com/2016/10/17/django從請求到返回都經歷了什麽/ 從runserver說起 ruserver是使用dja

Django請求返回經歷什麼

轉自 從runserver說起 ruserver是使用django自己的web server,主要用於開發和除錯中, 部署到線上環境一般使用nginx+uwsgi模式 manage.py 探祕 看一下manager.py的原始碼,你會發現上面的命令其實是通過Djan

瀏覽器的一個請求發送到返回經歷什麽

過程 通過 之間 get 設置 後臺 電平 head 標準 瀏覽器的一個請求從發送到返回都經歷了什麽,講的越詳細越好1、先從網絡模型層面:client (瀏覽器)與 server 通過 http 協議通訊,http 協議屬於應用層協議,http 基於 tcp 協議,所以

瀏覽器的一個請求發送到返回經歷什麽?

color 多次 標記 樣式表 -o 快遞 script 向上 ip地址解析 瀏覽器輸入url經歷圖 分析過程: 1.用戶輸入url,瀏覽器內部代碼將url進行拆分解析 url解析圖 2.瀏覽器首先去找本地的hosts文件,檢查在該文件中是否有相應的域名、IP對

http請求到響應經歷的階段 瀏覽器的一個請求傳送到返回經歷什麼?

瀏覽器的一個請求從傳送到返回都經歷了什麼?     瀏覽器輸入url經歷圖 分析過程: 1.使用者輸入url,瀏覽器內部程式碼將url進行拆分解析

瀏覽器的一個請求傳送到返回經歷什麼?

1.使用者輸入url,瀏覽器內部程式碼將url進行拆分解析 讓我們來看一個URL(統一資源定位器) scheme://login:password@address:port/path/to/resource/?query_string#fragment 1 : 協議名稱 2 :層級U

前端回答輸入URL到頁面展示經歷些什麽

自頂向下 ip) 生成 解析器 shee charset 網絡 結構 som 瀏覽器和服務器涉及大量網絡通信內容,此處做了弱化介紹,作為前端主要關註第四部分。一、 網絡環境保障我們先假定我們訪問的URL為www.abc.com並且地址不在局域網內;首先我們所處的局域網的總路

輸入網址到返回頁面經歷哪些過程?

開啟瀏覽器,在位址列中輸入baidu.com這個網址,會返回一個地址為https://www.baidu.com/的百度首頁。那麼,在這之間都發生了什麼呢? 在此期間經歷了四個過程,如下:域名解析:根據

輸入一個url到瀏覽器頁面展示經歷哪些過程

面試的時候有些面試官會問這個問題,可按如下流程作答: 1、首先,在瀏覽器位址列中輸入url 2、瀏覽器先檢視瀏覽器快取-系統快取-路由器快取,如果快取中有,會直接在螢幕中顯示頁面內容。若沒有,則跳到第三步操作。 3、在傳送http請求前,需要域名解析(DNS解析),解析

系統初期到支撐億級流量,經歷哪些架構的變遷?

## 寫在前面 > 隨著網際網路的發展,網際網路企業的業務也在不斷的飛速發展,進而導致系統的架構也在不斷的發生著變化。總體來說,系統的架構大致經歷了:單體應用架構—>垂直應用架構—>分散式架構—>SOA架構—>微服務架構的演變。當然,很多網際網路企業的系統架構已經向Servic

畢業後短時間內月薪翻倍的人,經歷什麽?(轉載)

... 讓我 經驗 不能 企業 成就感 薪水高 單位 and 畢業季,現在應屆生們坐在一起討(tu)論(cao)的,都是自己的新單位,和職場上那些新鮮又不知所措的第一次。 我們不畫成就感/自我實現的大餅,對於大多數的俗人來說,工作就是為了賺錢,尤其是對於剛畢業的學生,必然是

系統架構經歷怎樣的演變?

當今技術的發展日新月異,系統架構也跟隨技術的發展不斷升級和改進,從傳統的單一架構演變為如今的微服務分散式架構,我們來看看技術架構的演變過程。 NO.1 初期網站架構 網站建設初期,訪問人數有限,資料量不大,只需要一臺伺服器足矣,這時應用程式、檔案、資料庫等所有資源全部集中在這臺伺服器上,網站架構請看下

為祖國慶生, 我們經歷些什麼?

國慶節後的第一天上班,哎微博迪還好嗎? 看到小夥伴們的工作狀態,思緒不知道還在哪裡遊蕩 紛紛不在工作狀態 有望著電腦不知所云的 有打著字,但是電腦打著打著變黑屏的 有抱著杯子陷入沉思的 總結起來一句話,我不想上班!     國慶節,作為全

技本功丨智慧監控,在袋鼠雲日誌運用中經歷什麼……

  作者:大鵬 袋鼠雲日誌團隊後端開發工程師 傳統監控範圍小,智慧監控效率高,你說到底怎麼用?大鵬給你來支招~ 傳統監控是通過對監控項設定一個固定值(閾值),當監控項指標超過這個閾值時就通知人們關注這個指標項。傳統監控一般適用於一定範圍波動的業務指標: 比如磁碟的使

2018年,JavaScript經歷什麼?

摘要: 對JSer來說,這是很有意思的1年。 本文靈感來自JavaScript Weekly週報,歡迎大家訂閱。 The State of JavaScript 2018 The State of JavaScript調研已經連續做了3年(2016, 2017, 2018),今年一共調研了2萬多個JS開

2018 年,JavaScript 經歷什麼?

這些年,JavaScript生態系統異常活躍: ECMAScript打破多年的沉寂,每年都會給我們帶來新的特性,像async函式這種語法為開發者減少了大量冗餘的程式碼; JS大家庭的其他成員也都在進步,從前端到後端,從底層的JS引擎到上層的NPM庫,而大家熱愛的Vue正在重寫

2018年,JavaScript經歷什麼?

摘要: 對JSer來說,這是很有意思的1年。 本文靈感來自JavaScript Weekly週報,歡迎大家訂閱。 The State of JavaScript 2018 The State of JavaScript調研已經連續做了3年(2016, 2017,&nb

這些年,系統架構經歷怎樣的演變?

當今技術的發展日新月異,系統架構也跟隨技術的發展不斷升級和改進,從傳統的單一架構演變為如今的微服

區域網計算機間進行通訊經歷什麼

上圖中連線應該是雙向箭頭,這裡就不在進行修改了 區域網中A和B進行通訊,可以直接連線網線。但當局域網中計算機比較多的時候呢?都連線網線嗎?顯然這種做法不太行。由此交換機就應運而生。 區域網間多個計算機進行相互通訊,依靠的就是交換機。下面說一下計算機之間進行通訊的詳細流程。