django請求到響應的整個過程


一、項目初始化的核心模塊分析:

通過命令python manage.py runserver ip:port運行整個項目。 
執行完命令之后:
(1)在manage.py文件,添加settings.py的存儲路徑到系統環境變量中,方便其他django內置的模塊獲取settings.py文件中的內容;
(2)在manage.py文件,解析命令行參數:
①判斷項目的"啟動命令"。如果項目的啟動命令不是runserver,那么就不會進行啟動服務器相關的操作;
②如果是runserver,那么會進行啟動服務器相關的操作:
a、此時會解析ip、port,並且設置到變量中。(注意:如果沒有傳遞ip、port的話,那么會使用默認的ip和port,分別是127.0.0.1和8000);
 
b、django內部會調用 django.core.servers.basehttp.get_internal_wsgi_application返回一個WSGIHandler類的實例--wsgi_handler對象(也指application對象)。用來進行處理請求和響應數據等操作;
get_internal_wsgi_application源碼:
復制代碼
def get_internal_wsgi_application():
    from django.conf import settings
    app_path = getattr(settings, 'WSGI_APPLICATION')
    if app_path is None:
        return get_wsgi_application() (返回一個WSGIHandler實例)
    ...
復制代碼
WSGIHandler源碼:
復制代碼
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)
 
        response._handler_class = self.__class__
 
        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
        ]
        start_response(status, response_headers)
        if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
            response = environ['wsgi.file_wrapper'](response.file_to_stream)
        return response
復制代碼
 
c、django內部調用 django.core.servers.basehttp.run,同時將ip、port、wsgi_handler作為參數,生成一個WSGIServer服務器對象。用來進行接受請求,返回響應等操作。
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來監聽請求,通過WSGIHandler來處理請求。

二、項目運行時處理request和response的核心過程分析:

1、在項目運行過程中,一旦WSGIServer監聽到請求,那么WSGIServer會創建一個WSGIRequestHandler對象。通過調用WSGIRequestHandler對象的handler方法來處理請求。handler方法內部實際上是調用WSGIHandler對象來處理請求。(在調用WSGIHandler對象的時候會傳遞兩個參數:environ(請求的相關信息)、start_response(callback對象))
 
在WSGIHandler對象中的核心處理過程分析: (在其中處理request和response的過程中都會經過中間件)
 
a、 處理request:通過django.core.handlers.wsgi.WSGIRequest創建一個WSGIRequest對象,接受environ參數來處理request,然后生成一個request實例;
 
b、 獲取response:調用get_response方法處理響應信息,並構建一個response;
  在get_response方法中的核心處理過程分析:首先會加載Django項目的ROOT_URLCONF,然后根據url規則找到對應的視圖,視圖會根據request實例進行一定的業務邏輯處理然后生成一個具體的response。
 
c、調用WSGIServer的start_response方法設置status以及headers;
 
d、返回response到WSGIServer。
 

2、WSGIServer接受到response后,把status、headers、response以及其他相關的信息組合在一起構造成一個響應報文,然后返回給客戶端。

三、從請求到響應過程中與中間件的交互:

復制代碼
1.請求到達Request Middlewares,
2.URLConf通過urls.py文件和請求的URL找到相應的View
3.View Middlewares被訪問,它同樣可以對request做一些處理或者直接返回response
4.調用View中的函數
5.View中的方法可以選擇性的通過Models訪問底層的數據
6.所有的Model-to-DB的交互都是通過manager完成的
7.如果需要,Views可以使用一個特殊的Context
8.Context被傳給Template用來生成頁面
  a.Template使用Filters和Tags去渲染輸出
  b.輸出被返回到View
  c.HTTPResponse被發送到Response Middlewares
  d.任何Response Middlewares都可以豐富response或者返回一個完全不同的response
  e.Response返回到瀏覽器,呈現給用戶
復制代碼
 
注意:在MIDDLEWARE列表中,request是從上往下訪問的,而response、exception等都是從下往上訪問的。

中間件顧名思義,是介於request與response處理之間的一道處理過程,相對比較輕量級,並且在全局上改變django的輸入與輸出。因為改變的是全局,所以需要謹慎實用,用不好會影響到性能。

如果你想修改請求,例如被傳送到view中的HttpRequest對象。 或者你想修改view返回的HttpResponse對象,這些都可以通過中間件來實現。

可能你還想在view執行之前做一些操作,這種情況就可以用 middleware來實現。

Django默認的Middleware

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

process_view

process_exception

process_response

process_request,process_response

當用戶發起請求的時候會依次經過所有的的中間件,這個時候的請求時process_request,最后到達views的函數中,views函數處理后,在依次穿過中間件,這個時候是process_response,最后返回給請求者。

上述截圖中的中間件都是django中的,我們也可以自己定義一個中間件,我們可以自己寫一個類,但是必須繼承MiddlewareMixin

導入語法:

from django.utils.deprecation import MiddlewareMixin

in views:

def index(request):

    print("view函數...")
    return HttpResponse("OK")

in Mymiddlewares.py:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
 
    def process_response(self,request,response):
        print("Md1返回")
        return response

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2請求")
        #return HttpResponse("Md2中斷")
    def process_response(self,request,response):
        print("Md2返回")
        return response

結果:

Md1請求
Md2請求
view函數...
Md2返回
Md1返回

注意:如果當請求到達請求2的時候直接不符合條件返回,即return HttpResponse("Md2中斷"),程序將把請求直接發給中間件2返回,然后依次返回到請求者,結果如下:

返回Md2中斷的頁面,后台打印如下:

 

Md1請求
Md2請求
Md2返回
Md1返回

 

流程圖如下:

process_view

process_view(self, request, callback, callback_args, callback_kwargs)

Mymiddlewares.py修改如下

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
        #return HttpResponse("Md1中斷")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md1view")

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2請求")
        return HttpResponse("Md2中斷")
    def process_response(self,request,response):
        print("Md2返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md2view")

結果如下:
Md1請求
Md2請求
Md1view
Md2view
view函數...
Md2返回
Md1返回


免責聲明!

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



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