1. 程式人生 > >Django 中介軟體 Middleware

Django 中介軟體 Middleware

文章目錄

一、中介軟體

Middleware是Django請求/響應處理的外掛框架。它是一個輕巧的低階"外掛"系統,用於全域性改變Django的輸入或輸出。

每個中介軟體元件負責執行某些特定功能。例如,Django包含一箇中間件元件 AuthenticationMiddleware,它將使用者與使用會話的請求相關聯。

該文件介紹了中介軟體的工作原理,如何啟用中介軟體以及如何編寫自己的中介軟體。Django附帶了一些你可以直接使用的內建中介軟體。它們記錄在內建中介軟體參考中


二、啟用中介軟體

要啟用中介軟體,請將其新增到MIDDLEWARE Django設定中的列表中
如下,我激活了三個中介軟體 Middleware.test.m1,Middleware.test.m2,Middleware.test.m3

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',
    'Middleware.test.m1',
    'Middleware.test.m2',
    'Middleware.test.m3',
]

三、中介軟體請求和響應

在請求階段,呼叫views之前,django按照MIDDLEWARE_CLASSES中定義的順序從上到下呼叫中介軟體。

在Django中介軟體中,總共有分為從上到下hooks和從下到上hooks

從上到下hooks:

  • process_request()
  • process_view()

從下到上hooks:

  • process_exception()
  • process_template_response()
  • process_response()

四、中介軟體處理流程說明(如下述的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',
    'Middleware.test.m1',
    'Middleware.test.m2',
    'Middleware.test.m3',
]

一箇中間件最少有一個process_request hooks和一個process_response hooks,前者是用來處理請求的,後者是用來處理響應的

那除了必須的兩個hooks以外,還有其他三個hooks,分別是 process_view, process_exception, process_template_response

process_view 主要是用來執行middleware中具體的處理函式,如中介軟體請求中所說,是從上到下的hooks,表示process_view在views檢視函式之前執行

process_exception 一般情況下不會執行,只有在views檢視函式中出現exception異常時,才會執行;如中介軟體請求中所說,是從下到上的hooks,表示processs_exception在views檢視函式之後執行,也就是views檢視函數出錯之後,才會執行

processs_template_response 一般情況下也不會執行,也就是說,只有views中的函式返回物件中具有render方法,它才會執行


五、中介軟體處理順序(如下述的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',
    'Middleware.test.m1',
    'Middleware.test.m2',
    'Middleware.test.m3',
]

1、process_request 階段
當一個使用者發起請求後,該請求會經過上述的所有中介軟體,並且自上而下執行;先執行所有中介軟體的 process_request方法,該方法如果返回HttpResponse,則執行從當前的中介軟體向上執行 process_responsse,如果返回None,則接著向下執行 process_request

2、process_view 階段
當該使用者的請求執行完所有中介軟體 process_request 方法後,如果返回都為None,那麼接下來會執行所有中介軟體的 process_view 方法,如果其中一個 process_view 返回HttpResponse,則會跳過接下來所有中介軟體的 process_view,直接會從最下面的process_response自下而上執行,如果process_view返回None,則會繼續向下執行

3、views 階段
當該使用者的請求執行完所有的process_request和process_view階段,並且沒有返回HttpResponse;換句話說,返回的都是None,那麼這個時候就會到達views檢視函式

在這裡,可能會有三種可能性
(1) views中的函式返回物件中具有render方法
(2) views中的函式產生異常
(3) views中的函式返回物件中具有render方法,並且views中的函式產生異常

當出現第一種情況的時候,函式就會開始執行所有中介軟體的 process_template_response 方法,並且自下而上在每個中介軟體中挨個執行(當有定義 process_template_response 方法的時候)
當出現第二種情況的時候,函式就會開始執行所有中介軟體的 process_exception 方法,並且自下而上在每個中介軟體中挨個執行(當有定義 process_exception 方法的時候)
當出現第三種情況的時候,函式就會自下而上同時執行所有中介軟體中定義的 process_exception 和 process_template_response 方法(在這個時候會優先執行所有中介軟體中的process_template_response 方法,再執行所有中介軟體中的process_exception方法)

4、process_response 階段
當 process_request, process_view,views,process_template_response,process_exception 方法都執行完成後,開始自下而上從中介軟體中執行 process_response 方法,直到最上層中介軟體的 process_response 方法執行完畢,接著返回給使用者


六、Django 自定義中介軟體

1、在settings中定義三個中介軟體


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',
    'Middleware.test.m1',
    'Middleware.test.m2',
    'Middleware.test.m3',
]

2、建立中介軟體路徑

在專案跟路徑下面建立中介軟體路徑
./Middleware/test.py


3、定義中介軟體

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

class m1(MiddlewareMixin):
    def process_request(self, request):
        print('m1 request')

    def process_view(self, request, func_view, func_args, func_kwargs):
        print('m1 view')

    def process_response(self, request, response):
        print('m1 response')
        return response

    def process_exception(self, request, exception):
        print('m1 exception')

    def process_template_response(self, request, response):
        print('m1 template response')
        return response


class m2(MiddlewareMixin):
    def process_request(self, request):
        print('m2 request')

    def process_view(self, request, func_view, func_args, func_kwargs):
        print('m2 view')

    def process_response(self, request, response):
        print('m2 response')
        return response

    def process_exception(self, request, exception):
        print('m2 exception')

    def process_template_response(self, request, response):
        print('m2 template response')
        return response


class m3(MiddlewareMixin):
    def process_request(self, request):
        print('m3 request')

    def process_view(self, request, func_view, func_args, func_kwargs):
        print('m3 view')

    def process_response(self, request, response):
        print('m3 response')
        return response

    def process_exception(self, request, exception):
        print('m3 exception')

    def process_template_response(self, request, response):
        print('m3 template response')
        return response

4、定義檢視函式

class Foo:
    def render(self):
        int('v')
        return HttpResponse('OK')

def middleware(request):
    #return render(request, 'login.html')
    #return HttpResponse('middleware')
    return Foo()

七、一個請求經過中介軟體的請求週期

由於views檢視函式中有個報錯需要觸發中介軟體中定義的 process_exception 方法,所以便於展示執行順序,我去除了具體的報錯內容

m1 request
m2 request
m3 request
m1 view
m2 view
m3 view
m3 template response
m2 template response
m1 template response
m3 exception
m2 exception
m1 exception
m3 response
m2 response
m1 response


八、結論

大家可根據自己需求自行編寫中介軟體,並且測試中介軟體中每個方法的執行順序,總共有5個方法,分別為
process_request
process_view
process_template_response
process_exception
process_response

另外:
Django 官方不建議在中介軟體層處理 request.POST 資料,csrf中介軟體是個例外,因為要全域性安全處理使用者token