【Django--中間件】

2022-12-19 12:22:36 來源:51CTO博客

一、什么是中間件

Django 中間件是是介于request與response處理之間的一道處理過程,是修改 Django request 或者 response 對象的鉤子,相對比較輕量級,并且在全局上改變django的輸入與輸出。django中間價官網定義:

Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.

瀏覽器從請求到響應的過程中,Django 需要通過很多中間件來處理,可以看如下圖所示:


(資料圖片僅供參考)

中間件

二、中間件的作用

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

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

Django默認的中間件:(在django項目的settings模塊中,有一個 MIDDLEWARE變量,其中每一個元素就是一個中間件,如下)

MIDDLEWARE = [    "django.middleware.security.SecurityMiddleware",    "django.contrib.sessions.middleware.SessionMiddleware",    # 需要添加在CommonMiddleware中間件之前    "corsheaders.middleware.CorsMiddleware",    "django.middleware.common.CommonMiddleware",    # "django.middleware.csrf.CsrfViewMiddleware",    "django.contrib.auth.middleware.AuthenticationMiddleware",    "django.contrib.messages.middleware.MessageMiddleware",    "django.middleware.clickjacking.XFrameOptionsMiddleware",]

請求進來是自上而下,通過反射找到類,用for循環來執行,可以自定義中間件,但是也要寫在MIDDLEWARE中,可以在app01下創建一個mymid.py文件來寫我們自定義的中間件

每一個中間件都有具體的功能

django自帶的中間件

中間件可以定義五個方法(主要的是process_request和process_response),分別是:

a.def process_request(self, request):    在請求之前會自動執行b.def process_view(self, request, callback, callback_args, callback_kwargs):    在執行視圖函數或者視圖方法之前會自動執行c.def process_template_response(self, request, response):    在模板渲染之前(前后端不分離)會自動執行d.def process_response(self, request, response):    在執行視圖函數或者視圖方法之后會自動執行e.def process_exception(self, request, exception):    在執行視圖函數或者視圖方法中間,出現異常時會自動執行

以上方法的返回值可以是None或一個HttpResponse對象,如果是None,則繼續按照django定義的規則向后繼續執行,如果是HttpResponse對象,則直接將該對象返回給用戶。

中間件執行過程:

在request請求執行之前,執行process_request中間件,在view視圖函數執行之前,執行process_view中間件,如果是前后端不分離的項目模板渲染之前會自動執行process_template_response中間件,前后端分離項目在view視圖函數執行之后,會執行process_response中間件,如果在執行視圖函數中間出現異常時,會自動執行process_exception中間件。

三、自定義中間件

1、process_request和process_response

1.1 自定義handle_middilewares.py

我們也可以自己定義一個中間件,自己寫一個類,但是必須繼承MiddlewareMixin

#file:handle_middilewares.pyfrom django.utils.deprecation import MiddlewareMixinfrom django.shortcuts import HttpResponseclass Md1(MiddlewareMixin):    def process_request(self,request):        print("Md1請求")     def process_response(self,request,response):        print("Md1返回")        return responseclass Md2(MiddlewareMixin):    def process_request(self,request):        print("Md2請求")        #return HttpResponse("Md2中斷")    def process_response(self,request,response):#        print("Md2返回")        return response
1.2、django中創建一個視圖函數或者視圖類

此處操作略過,用已有項目演示

1.3、在settings.py的MIDDLEWARE里注冊自己定義的中間件

調用項目的視圖函數(調用項目接口),后臺打印內容:

Md1請求Md2請求此處已調用視圖函數Md2返回Md1返回[20/Oct/2020 11:44:49] "GET /projects/?page=1&size=3 HTTP/1.1" 200 965

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

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

Md1請求Md2請求Md2返回Md1返回[20/Oct/2020 11:47:52] "GET /projects/?page=1&size=3 HTTP/1.1" 200 9

接口調用結果:

流程圖如下:

由此總結一下:

中間件的process_request方法是在執行視圖函數之前執行的。當配置多個中間件時,會按照MIDDLEWARE中的注冊順序,也就是列表的索引值,從前到后依次執行的。不同中間件之間傳遞的request都是同一個對象多個中間件中的process_response方法是按照MIDDLEWARE中的注冊順序倒序執行的,也就是說第一個中間件的process_request方法首先執行,而它的process_response方法最后執行,最后一個中間件的process_request方法最后一個執行,它的process_response方法是最先執行。

2、process_view

process_view(self, request, view_func, view_args, view_kwargs)該方法有四個參數

request是HttpRequest對象。view_func是Django即將使用的視圖函數。 (它是實際的函數對象,而不是函數的名稱作為字符串。)view_args是將傳遞給視圖的位置參數的列表(無名分組分過來的值).view_kwargs是將傳遞給視圖的關鍵字參數的字典(有名分組分過來的值)。 view_args和view_kwargs都不包含第一個視圖參數(request)。

Django會在調用視圖函數之前調用process_view方法。

它應該返回None或一個HttpResponse對象。 如果返回None,Django將繼續處理這個請求,執行任何其他中間件的process_view方法,然后在執行相應的視圖。 如果它返回一個HttpResponse對象,Django不會調用適當的視圖函數。 它將執行中間件的process_response方法并將應用到該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請求Md1viewMd2view此處已調用視圖函數Md2返回Md1返回[20/Oct/2020 14:15:00] "GET /projects/?page=1&size=3 HTTP/1.1" 200 965

下圖進行分析上面的過程:

當最后一個中間的process_request到達路由關系映射之后,返回到中間件1的process_view,然后依次往下,到達views函數,最后通過process_response依次返回到達用戶

注意:process_view如果有返回值,會越過其他的process_view以及視圖函數,返回process_view的返回值,但是所有的process_response都還會執行。

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):        return HttpResponse("hello")        # response=callback(request,*callback_args,**callback_kwargs)        # return responseclass Md2(MiddlewareMixin):    def process_request(self,request):        print("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請求Md2返回Md1返回[20/Oct/2020 14:29:33] "GET /projects/?page=1&size=3 HTTP/1.1" 200 5

3、process_exception

process_exception(self, request, exception)

該方法兩個參數:

一個HttpRequest對象一個exception是視圖函數異常產生的Exception對象。

這個方法只有在視圖函數中出現異常了才執行,它返回的值可以是一個None也可以是一個HttpResponse對象。如果是HttpResponse對象,Django將調用模板和中間件中的process_response方法,并返回給瀏覽器,否則將默認處理異常。

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")    def process_exception(self, request, exception):        print("md1 process_exception...")        return HttpResponse("VIEW異常")class Md2(MiddlewareMixin):    def process_request(self,request):        print("Md2請求")    def process_response(self,request,response):        print("Md2返回")        return response    def process_view(self, request, callback, callback_args, callback_kwargs):        print("Md2view")    def process_exception(self, request, exception):  # 只有報錯了才會執行exception        print("md2 process_exception...")

執行后:

Md1請求Md2請求Md1viewMd2view此處已調用視圖函數[20/Oct/2020 14:43:53] "GET /projects/?page=1&size=3 HTTP/1.1" 200 10md2 process_exception...md1 process_exception...Md2返回Md1返回

如果第一個process_exception返回一個None(或者沒有return),則交給下一個中間件的process_exception方法來處理異常。它的執行順序也是按照中間件注冊順序的倒序執行。

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")    def process_exception(self, request, exception):        print("md1 process_exception...")class Md2(MiddlewareMixin):    def process_request(self,request):        print("Md2請求")    def process_response(self,request,response):        print("Md2返回")        return response    def process_view(self, request, callback, callback_args, callback_kwargs):        print("Md2view")    def process_exception(self, request, exception):  # 只有報錯了才會執行exception        print("md2 process_exception...")        return HttpResponse("VIEW異常--md2")

執行結果:

Md1請求Md2請求Md1viewMd2view此處已調用視圖函數md2 process_exception...Md2返回Md1返回

當views出現錯誤時,流程圖如下:

4、process_template_response(self,request,response)

該方法對視圖函數返回值有要求,必須是一個含有render方法類的對象,才會執行此方法

四 中間件應用場景

1、做IP訪問頻率限制

某些IP訪問服務器的頻率過高,進行攔截,比如限制每分鐘不能超過20次。

2、URL訪問過濾

如果用戶訪問的是login視圖(放過)

如果訪問其他視圖,需要檢測是不是有session認證,已經有了放行,沒有返回login,這樣就不需要在多個視圖函數上寫驗證登錄狀態的裝飾器了!

標簽: 后臺打印

上一篇:計算存儲分離在京東云消息中間件JCQ上的應用
下一篇:AWS 下 EKS 部署 Dashboard