首頁 >頭條 > 正文

      動態:Django筆記二十九之中間件介紹

      2023-04-23 21:23:08來源:博客園

      本文首發于公眾號:Hunter后端原文鏈接:Django筆記二十九之中間件介紹


      (資料圖片僅供參考)

      這一節介紹一下 Django 的中間件。

      關于中間件,官方文檔的解釋為:中間件是一個嵌入 Django 系統的 request 和 response 的鉤子框架,是一個能夠全局改變 Django 輸入/輸出的系統。

      我們可以這樣理解,一個 request 請求發送到 Django 系統的過程中,在經過路由和視圖的處理前,會先經過一層處理,這個處理操作可以是日志記錄,可以是登錄驗證甚至你想在系統里定義的功能,這個操作就是中間件實現的功能。

      接下來我們將通過一個記錄請求的 ip 的功能的介紹來介紹一下中間件的實現流程。

      以下是本篇筆記目錄:

      請求經過 Django 然后返回的流程HttpRequest 和 HttpResponse 介紹中間件的示例介紹記錄訪問 ip 的功能實現1、請求經過 Django 然后返回的流程

      首先,前端發起一個請求,這個請求經由 web 服務器轉發給 Django 系統,在進入 Django 系統后會先經過一系列的中間件的功能處理。

      這個中間件會在 settings.py 里定義,Django 系統默認自帶的中間件列表如下:

      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",]

      這些中間件我們也可以根據自己的需求自己定義,比如新加一個登錄權限,或者日志記錄,或者對輸入的參數進行格式化處理也可以,或者自己想要設置的其他功能也行,具體怎么設置在后面介紹。

      在中間件處理的流程中,請求會被按照順序從上往下處理。

      這個流程過后,一個 request 請求才會被進行 URL 的路徑匹配,如果匹配上,再去找相應的 views 視圖函數進行數據處理

      views 處理完之后,會形成一個 response,返回,然后再次經歷這個中間件處理,因為在每一層中間件中都類似于一種嵌套,所以返回 response 的時候,是從下往上再次處理 response 的。

      中間件處理結束之后再被返回出去,給到前端。

      在這整個流程處理中,可以說中間件是進行了兩次操作,一個是進入的時候處理 request,一個是返回的時候處理 response。

      2、HttpRequest 和 HttpResponse 介紹

      我們先來看一個視圖函數:

      def time_view(request):    now = datetime.datetime.now()    html = "

      now: %s

      abc\nabc" % now return HttpResponse(html)

      當 Django 接收到一個請求,系統會創建一個 HttpRequest 對象,這個對象就是上面的視圖函數里的輸入參數,request

      在對數據進行處理后,系統會返回一個 HttpResponse 對象,這個就是我們 return 的內容。

      在一個 HttpRequest 對象里,會包含請求的路徑、參數、請求方式、 cookie 等一切請求過來時的數據,我們可以在請求的時候根據需要存取。

      在返回的 HttpResponse 中,可以是一個 html 頁面,也可以是 json 格式的數據,內容是可以自定義的,只要前端可以做相應的處理。

      3、中間件的示例介紹

      接下來我們定義一個中間件,結構大致如下:

      # huter/middleware.pyclass SimpleMiddleware:    def __init__(self, get_response):        self.get_response = get_response    def __call__(self, request):        # 在請求進入視圖函數前的可以執行一些操作,針對 request        print(request.path)        response = self.get_response(request)                # 在處理完請求后,可以執行一些操作,針對 response        # log_response_info()        return response

      然后我們在 sttings.py 里引入這個中間件,我們放到 MIDDLEWARE 列表的最下面,說明這個中間件會在其他中間件處理完 request 之后再處理:

      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",    "hunter.middleware.TestMiddleware",]

      在 SimpleMiddleware 這個類里,call() 函數會自動調用,其中有一行,response = self.get_response(request)

      在這一行函數之前,可以對請求的 request 做處理,包括我們前面說的各種功能,比如日志、登錄驗證、參數格式化等

      在這一行函數之后,獲取了 response,這個就是視圖函數返回的 HttpResponse,我們可以在這里對它的 response.status_code 狀態碼,和 response.content 做處理

      比如前面 time_view 函數返回的內容是一個 JsonResponse:

      return JsonResponse({"code": 0})

      那么在這里我們可以獲取然后處理這個 HttpResponse:

      def __call__(self, request):    response = self.get_response(request)    content = json.loads(response.content)    content["msg"] = "success"    response.content = json.dumps(content)    return response

      這里只是一個示例,因為并不是所有的 HttpResponse 都是 json 格式的數據,所以可能需要加一個 try except 做下處理

      還有一個功能是我之前做過的,就是在 headers 中加一個特定的字符串,表示是我們系統專有的,用于前端判斷,這個很簡單,就是在 response 的 headers 參數中加一個鍵值對:

      response.headers["system"] = "hunter"

      以上就是一個最簡單的中間件的處理方式。

      process_view

      除了 call函數以外,還有一個 process_view() 的函數

      這個函數是在 Django 系統調用 views 視圖函數前被調用,它的返回值是 None 或者一個 HttpResponse

      如果為 None,那么系統會接著調用視圖函數,如果是 HttpResponse 作為返回值,說明系統在這里已經處理了請求,不需要再走views視圖函數,然后就會直接返回。

      我們通過下面的例子來解釋這個函數作用。

      4、記錄訪問 ip 的功能實現

      假設我們需要禁止某一個或者某一個 ip 列表的請求訪問我們的系統

      當然,這個操作,在 web 服務器那部分就可以攔截,這里就是單純舉個例子

      那么我們這樣設置一個 process_view 的功能,在真正執行視圖函數(也就是url 匹配上的 view函數)前,取出這個 request 的訪問的ip,然后進行判斷,如果在 禁止列表,那么則直接返回一個禁止訪問的頁面。

      class TestMiddleware:    def __init__(self, get_response):        self.get_response = get_response    def __call__(self, request):        response = self.get_response(request)        return response    def process_view(self, request, view_func, *view_args, **view_kwargs):        EXCLUDE_IPS = ["192.168.1.54"]        if "HTTP_X_FORWARDED_FOR" in  request.META:            ip =  request.META["HTTP_X_FORWARDED_FOR"]        else:            ip = request.META["REMOTE_ADDR"]        if ip in EXCLUDE_IPS:            return HttpResponse("

      您的ip被禁止

      ") return None

      在這里,我們拿到請求的 ip 地址,去和我們定義的禁止ip列表做比較

      如果在禁用列表,則直接返回 HttpResponse,不接著請求我們的服務來

      否則,就返回 None,系統接收到 None 之后,會接著往下處理。

      如果想獲取更多后端相關文章,可掃碼關注閱讀:

      責任編輯:

      標簽:

      免責聲明

      頭條新聞