1. 程式人生 > 實用技巧 >Django中介軟體middleware的使用

Django中介軟體middleware的使用

摘要

Django 中的中介軟體(middleware),是一個鑲嵌到Django的request/response處理機制中的一個hooks框架,是一個修改django全域性輸入輸出的一個底層外掛系統。讓我們可以自定義想要的一些功能來處理使用者的請求。

在Django中,中介軟體其實就是一個類,在類中包含一組特定的功能,在請求到來或者結束時,Django會根據我們定義的中介軟體規則執行中介軟體中對應的方法,一個 Django 專案預設啟用的中介軟體在我們專案中的配置中可以看到是這個樣子的:

settings.py

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這裡列表中的每一個元素,其實就是一個個單獨的中介軟體,舉例來說:django.middleware.csrf.CsrfViewMiddleware這個中介軟體,作用就是在我們的 form 表單提交請求的時候,提交的時候必須要帶上csrf_token,否則就不會正確提交。

中介軟體使用也需要講究順序,下一層依賴上一層的封裝,例如,我們的AuthenticationMiddleware是一個認證中介軟體,在session 中儲存認證使用者的資訊,但是他必須依賴於SessionMiddleware才可以被正確使用,所以他也必須在SessionMiddleware之後。但是具體的順序問題可以參考

這裡

中介軟體結構

中介軟體類中需要包含以下處理方法:

1. process_request(self, request)
2. process_view(self, request, callback, callback_args, callback_kwargs)
3. process_template_response(self, request, response)
4. process_exception(self, request, exception)
5. process_response(self, request, response)

執行過程

以我們的專案中預設中介軟體為例子,具體的流程如下所示:

中介軟體執行前提

中介軟體要按照一定的順序一層一層的執行下去,需要按照標準返回特定的內容:

  • 如果為 None,則按照順序繼續向下執行
  • 如果為 HttpResonse 物件,則直接將這個物件返回給使用者

此處有一個版本前後的區別,請大家注意區分:

在 Django1.10之後, 當某個中介軟體,例如CsrfViewMiddleware請求process_request沒有返回 None 後,這個請求會交給CsrfViewMiddleware的process_response來返回,即返回給相同一層的中介軟體來返回:

在 Django1.10之前的版本,會返回到最底層的中介軟體來返回:

中介軟體方法:

1、process_request(self, request)

其中request引數就是我們的HttpRequest物件,process_request 會在每個request在被決定使用哪個view之前呼叫,它會返回None或HttpResponse物件

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

其中request引數就是的HttpRequest物件,callback 就是請求被決定使用的 view 函式,書具體的函式名,不是字串型別。callback_args和callback_kwargs是 view 函式需要接受的引數,它會返回None或HttpResponse物件

3、process_template_response(self, request, response)

其中request 是 HttpRequest 物件, response 是一個由Django view或者中介軟體返回的TemplateResponse 物件,process_template_response()在 view 使用 render 渲染一個模版物件完成之後被呼叫,它必須返回一個render 方法執行後的response物件。

4、process_exception(self, request, exception)

其中request引數就是的HttpRequest物件,exception是view函式中raise的Exception物件,當 view 函式 raise 一個 exception 的時候呼叫process_exception,它會返回None或HttpResponse物件

5、process_response(self, request, response)

其中request是 HttpRequest 物件,response 是一個django view或者中介軟體返回的 HttpResponse 或者StreamingHttpResponse物件,process_response會在所有響應到達瀏覽器之前被呼叫

class MiddleWareTest(MiddlewareMixin):

    # def __init__(self):
    #
    #     print('web start at hear')

    def process_request(self, request):

        print('after request before urls')

        return None

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

        print('after urls before view')

        return

    def process_template_response(self, request, response):

        print('after view(use render) before response')

        return response

    def process_response(self, request, response):

        print('after view before response')

        return response

    def process_exception(self, request, execption):

        print('when view raise error ')

中介軟體的詳細執行流程

由於process_template_response在特定的 rander 渲染中才會被呼叫,所以過程中不新增該方法

自建中介軟體與執行過程測試

為了更加清晰的展示中介軟體的執行過程與如何自定義一箇中間件,我們模擬一個簡單的使用者請求和中介軟體執行過程:

自定義中介軟體

from django.utils.deprecation import MiddlewareMixin
class MyMiddleware_1(MiddlewareMixin):
 def process_request(self, request):
  print("自定義 process_request 1")
  return None
 
 def process_response(self, request, response):
  print("自定義 process_response 1")
  return response
 
 def process_view(self, request, callback, callback_args, callback_kwargs):
  print("自定義 process_view 1")
  return None
 
 def process_exception(self, request, exception):
  print("自定義 process_exception 1")
 
 
class MyMiddleware_2(MiddlewareMixin):
 
 def process_request(self, request):
  print("自定義 process_request 2")
  return None
 
 def process_response(self, request, response):
  print("自定義 process_response 2")
  return response
 
 def process_view(self, request, callback, callback_args, callback_kwargs):
  print("自定義 process_view 2")
  return None
 
 def process_exception(self, request, exception):
  print("自定義 process_exception 2")

引入

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',
 'app01.middle_by_me.MyMiddleware_1', # 第一個自定義 middleware
 'app01.middle_by_me.MyMiddleware_2' # 第二個自定義 middleware
]

輸出結果

自定義中介軟體應用場景

在不修改業務邏輯原始碼的情況下,可以使用中介軟體來對使用者的訪問進行一定的篩選過濾,或者訪問控制。

還有就是是當源站的 CDN,請求穿透源站,middleware 判斷請求的內容是否在快取中,如果在快取直接返回,而可以不經過業務後端邏輯,類似於給web網站新增一個cache層;