天天看點

060.Python元件-中間件

一 中間件基本介紹

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

Django的中間件的定義:

中間件是 Django 用來處理請求和響應的鈎子架構。它是一個輕量級的、底層級的“插件”系統,用于全局性地控制Django 的輸入或輸出,可以了解為内置的app或者小架構。

如果想修改請求,例如被傳送到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',
]      

MIDDLEWARE配置項是一個清單,清單中是一個個字元串,這些字元串其實是一個個類,也就是一個個中間件。cnfs也是一個中間件

二 自建一個中間件

2.1 process_request中間件

root@darren-virtual-machine:~/PycharmProjects/cookie_seesion# vim cookie/Middlewares.py

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print("MD1下的process_request 方法")


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2下的process_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',
    'cookie.Middlewares.MD1',
    'cookie.Middlewares.MD2',
]      

通路http://127.0.0.1:8000/cookie/login/,調試結果如下

MD1下的process_request 方法
MD2下的process_request 方法      

這裡的結果是按照注冊順序執行的

配置views

from django.shortcuts import render,redirect,HttpResponse

# Create your views here.
def login_required(func):
    def inner(request,*args,**kwargs):
        if not request.COOKIES.get("is_login"):
            return redirect("/cookie/login/")
        rep = func(request,*args,**kwargs)
        return rep
    return inner

@login_required
def index(request):
#    if not request.COOKIES.get("is_login"):
#        return redirect("/cookie/login/")
    print("index 視圖")
    return render(request,"index.html")
def login(request):
    if request.method == "GET":
        return  render(request,"login.html")
    else:
        username = request.POST.get("username")
        password = request.POST.get("password")
        if username == "joy" and password == "123456":
            rep = redirect("/cookie/index/")
            rep.set_cookie("is_login",True)
            return rep
        else:
            return redirect("/cookie/login/")
def loginout(request):
    rep = redirect("/cookie/login/")
    rep.delete_cookie("is_login")
    return rep

@login_required
def order(request):
#    if not request.COOKIES.get("is_login"):
#        return redirect("/cookie/login/")
    return HttpResponse("oreder success")      

登入檢視結果

MD1下的process_request 方法
MD2下的process_request 方法
index 視圖      

process_request是在view之後輸出的

2.2 process_reponse中間件

通路報錯

060.Python元件-中間件

這是因為在request,必須有回應

輸出結果

MD1下的process_request 方法
MD2下的process_request 方法
MD2下的process_reponse 方法
MD1下的process_reponse 方法      

先執行response的MD2

060.Python元件-中間件

添加響應

結果

MD1下的process_request 方法
MD2下的process_request 方法
index 視圖
MD2下的process_reponse 方法
MD1下的process_reponse 方法      

在return response傳回的對象就是

驗證:

views檔案

from django.shortcuts import render,redirect,HttpResponse

# Create your views here.
def login_required(func):
    def inner(request,*args,**kwargs):
        if not request.COOKIES.get("is_login"):
            return redirect("/cookie/login/")
        rep = func(request,*args,**kwargs)
        return rep
    return inner

@login_required
def index(request):
#    if not request.COOKIES.get("is_login"):
#        return redirect("/cookie/login/")
    print("index 視圖")
    rep = render(request,"index.html")
    print(id(rep))
    return rep
def login(request):
    if request.method == "GET":
        return  render(request,"login.html")
    else:
        username = request.POST.get("username")
        password = request.POST.get("password")
        if username == "joy" and password == "123456":
            rep = redirect("/cookie/index/")
            rep.set_cookie("is_login",True)
            return rep
        else:
            return redirect("/cookie/login/")
def loginout(request):
    rep = redirect("/cookie/login/")
    rep.delete_cookie("is_login")
    return rep

@login_required
def order(request):
#    if not request.COOKIES.get("is_login"):
#        return redirect("/cookie/login/")
    return HttpResponse("oreder success")      

中間件

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print("MD1下的process_request 方法")
    def process_response(self,request,response):
        print("MD1下的process_reponse 方法")
        print(id(response))
        return response

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2下的process_request 方法")
    def process_response(self,request,response):
        print("MD2下的process_reponse 方法")
        return response      

通路結果,是一緻的

MD1下的process_request 方法
MD2下的process_request 方法
index 視圖
139857132829104
MD2下的process_reponse 方法
MD1下的process_reponse 方法
139857132829104      

是以上面錯誤的原因,是因為resonse沒有傳回值,則預設的傳回值為null,導緻報錯,傳回response後,就是傳回render(request,"index.html")

在request添加傳回值

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,redirect,HttpResponse
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print("MD1下的process_request 方法")
        return HttpResponse("Hello  我來了")
    def process_response(self,request,response):
        print("MD1下的process_response 方法")
        print(id(response))
        return response

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2下的process_request 方法")
    def process_response(self,request,response):
        print("MD2下的process_response 方法")
        return response      

通路http://127.0.0.1:8000/cookie/login/,沒有到view層

060.Python元件-中間件

輸出

MD1下的process_request 方法
MD1下的process_response 方法
140023033668160      
060.Python元件-中間件

如圖,當reques的中間件中,有傳回值,就會直接傳回,不會走到下面的reques和視圖層,生命請求周期如下:

060.Python元件-中間件

2.3 process_view方法

該方法有四個參數

  • 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并傳回結果。

添加process_view

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,redirect,HttpResponse
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print("MD1下的process_request 方法")
        #return HttpResponse("Hello  我來了")
    def process_response(self,request,response):
        print("MD1下的process_response 方法")
        #print(id(response))
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD1下的process_view 方法")

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2下的process_request 方法")
    def process_response(self,request,response):
        print("MD2下的process_response 方法")
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD2下的process_view 方法")      
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 視圖
MD2下的process_response 方法
MD1下的process_response 方法      

process_view方法是在process_request之後,視圖函數之前執行的,執行順序按照MIDDLEWARE中的注冊順序從前到後順序執行。

060.Python元件-中間件

 在MD1下的porcess_view傳回一個傳回值

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,redirect,HttpResponse
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print("MD1下的process_request 方法")
        #return HttpResponse("Hello  我來了")
    def process_response(self,request,response):
        print("MD1下的process_response 方法")
        #print(id(response))
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD1下的process_view 方法")
        return view_func(request)
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2下的process_request 方法")
    def process_response(self,request,response):
        print("MD2下的process_response 方法")
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD2下的process_view 方法")      

執行結果

MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
index 視圖
MD2下的process_response 方法
MD1下的process_response 方法      

2.4 process_exception

文法:

process_exception(self, request, exception)

該方法兩個參數:

  • HttpRequest對象
  • exception是視圖函數異常産生的Exception對象。

  這個方法隻有在視圖函數中出現異常了才執行,它傳回的值可以是一個None也可以是一個HttpResponse對象。如果是HttpResponse對象,Django将調用模闆和中間件中的process_response方法,并傳回給浏覽器,否則将預設處理異常。如果傳回一個None,則交給下一個中間件的process_exception方法來處理異常。它的執行順序也是按照中間件注冊順序的倒序執行。

添加process_exception

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,redirect,HttpResponse
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print("MD1下的process_request 方法")
        #return HttpResponse("Hello  我來了")
        
    def process_response(self,request,response):
        print("MD1下的process_response 方法")
        #print(id(response))
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD1下的process_view 方法")
        #return view_func(request)

    def process_exception(self,request,exception):
        print("MD1下的process_exception 方法")
        
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2下的process_request 方法")
        
    def process_response(self,request,response):
        print("MD2下的process_response 方法")
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD2下的process_view 方法")
        
    def process_expection(self,request,exception):
        print("MD2下的process_exception 方法")      

通路結果

MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 視圖
MD2下的process_response 方法
MD1下的process_response 方法      

并沒有exception,是因為需要view異常才會觸發

制造views異常

from django.shortcuts import render,redirect,HttpResponse

# Create your views here.
def login_required(func):
    def inner(request,*args,**kwargs):
        if not request.COOKIES.get("is_login"):
            return redirect("/cookie/login/")
        rep = func(request,*args,**kwargs)
        return rep
    return inner

@login_required
def index(request):
#    if not request.COOKIES.get("is_login"):
#        return redirect("/cookie/login/")
    print("index 視圖")
    int("aaa")
    rep = render(request,"index.html")
    #print(id(rep))
    return rep
def login(request):
    if request.method == "GET":
        return  render(request,"login.html")
    else:
        username = request.POST.get("username")
        password = request.POST.get("password")
        if username == "joy" and password == "123456":
            rep = redirect("/cookie/index/")
            rep.set_cookie("is_login",True)
            return rep
        else:
            return redirect("/cookie/login/")
def loginout(request):
    rep = redirect("/cookie/login/")
    rep.delete_cookie("is_login")
    return rep

@login_required
def order(request):
#    if not request.COOKIES.get("is_login"):
#        return redirect("/cookie/login/")
    return HttpResponse("oreder success")      

通路http://127.0.0.1:8000/cookie/index/

060.Python元件-中間件

 輸出結果

MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 視圖
MD2下的process_exception 方法
MD1下的process_exception 方法
MD2下的process_response 方法
MD1下的process_response 方法       

在exception添加錯誤傳回

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,redirect,HttpResponse
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print("MD1下的process_request 方法")
        #return HttpResponse("Hello  我來了")

    def process_response(self,request,response):
        print("MD1下的process_response 方法")
        #print(id(response))
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD1下的process_view 方法")
        #return view_func(request)

    def process_exception(self,request,exception):
        print("MD1下的process_exception 方法")
        return HttpResponse(exception)

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2下的process_request 方法")

    def process_response(self,request,response):
        print("MD2下的process_response 方法")
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD2下的process_view 方法")

    def process_exception(self,request,exception):
        print("MD2下的process_exception 方法")      

通路結果沒有報錯

060.Python元件-中間件
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 視圖
MD2下的process_exception 方法
MD1下的process_exception 方法
MD2下的process_response 方法
MD1下的process_response 方法      

在MD2傳回

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,redirect,HttpResponse
class MD1(MiddlewareMixin):
    def process_request(self,request):
        print("MD1下的process_request 方法")
        #return HttpResponse("Hello  我來了")

    def process_response(self,request,response):
        print("MD1下的process_response 方法")
        #print(id(response))
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD1下的process_view 方法")
        #return view_func(request)

    def process_exception(self,request,exception):
        print("MD1下的process_exception 方法")


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2下的process_request 方法")

    def process_response(self,request,response):
        print("MD2下的process_response 方法")
        return response

    def process_view(self,request,view_func,view_args,view_kwargs):
        print("MD2下的process_view 方法")

    def process_exception(self,request,exception):
        print("MD2下的process_exception 方法")
        return HttpResponse(exception)      
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 視圖
MD2下的process_exception 方法
MD2下的process_response 方法
MD1下的process_response 方法      

沒有MD1的exception,已經跳過,流程如下

060.Python元件-中間件

綠色為正常流程,紅色是則MD2添加return傳回

作者:夢中淚

出處:http://www.cnblogs.com/zyxnhr/

關于作者:雲計算,linux,虛拟化,存儲

---------------------------------------------------------------------------

個性簽名:我以為我很頹廢,今天我才知道,原來我早報廢了。

如果覺得本篇文章最您有幫助,歡迎轉載,且在文章頁面明顯位置給出原文連結!記得在右下角點個“推薦”,部落客在此感謝!