Django中間件 ---- 第19章

1. 中間件執行流程

Django 1.10之前,請求到達第一個中間件,會找到最後一箇中間件的 process_response 返回:
在這裏插入圖片描述

而Django 1.10之後,會找到自己的 process_response 返回:
在這裏插入圖片描述

中間件是有序執行的!

2. 中間件原理淺析

中間件是類,首先查看Django源碼中的中間件:
在這裏插入圖片描述
在這裏插入圖片描述
所以,我們寫的中間件也要繼承MiddlewareMixin類,這裏把中間件類寫在middleware.py,並放置在與manage.py同級目錄下:

middleware.py:

from django.utils.deprecation import MiddlewareMixin

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

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

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

    def process_response(self, request, response):
        print('m2.process_response')
        return response
"""
m1.process_request
m2.process_request
test
m2.process_response
m1.process_response
"""

還要在配置文件 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.M1',
    'middleware.M2'
]

可以看到 先執行process_request再執行process_response。還有個process_view方法:

from django.utils.deprecation import MiddlewareMixin

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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print('m1.process_view')
        # return callback(*callback_args, **callback_kwargs)

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

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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print('m2.process_view')
        # return callback(*callback_args, **callback_kwargs)

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

"""
m1.process_request
m2.process_request
m1.process_view
m2.process_view
test
m2.process_response
m1.process_response
"""

process_request有返回值會直接執行自己的process_response。如果執行的是process_view有返回值,會跳過下一個中間件的process_view,執行視圖函數(這裏是自動調用的)。接下來,不是執行自己的process_response返回給用戶,而是 最開始 的process_response(把所有的process_response都執行一遍):

from django.utils.deprecation import MiddlewareMixin


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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        # print(callback, callback_args, callback_kwargs) #<function test at 0x7fd39b986040> () {}
        print('m1.process_view')
        response = callback(request, *callback_args, **callback_kwargs)
        return response

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


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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print('m2.process_view')

    def process_response(self, request, response):
        print('m2.process_response')
        return response
        
"""
m1.process_request
m2.process_request
m1.process_view
test
m2.process_response
m1.process_response
"""

中間件的類中還有 process_exception 方法,這是關於異常的方法。爲了進行測試首先在視圖函數中使代碼產生異常:

def test(request):
    print('test')
    a = int('erics')
    return HttpResponse()

通過下面的代碼測試發現,請求經過所有的process_request、process_view到達視圖函數,沒有錯誤的情況下會執行process_response,出現錯誤會執行process_exception在執行process_response:

from django.utils.deprecation import MiddlewareMixin

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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        # print(callback, callback_args, callback_kwargs) #<function test at 0x7fd39b986040> () {}
        print('m1.process_view')
        # response = callback(request, *callback_args, **callback_kwargs)
        # return response
    #
    def process_response(self, request, response):
        print('m1.process_response')
        return response

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


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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print('m2.process_view')

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

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

"""
m1.process_request
m2.process_request
m1.process_view
m2.process_view
test
m2.process_exception
m1.process_exception
m2.process_response
m1.process_response
"""

在process_exception使用HttpResponse函數返回異常,可以看這個時候中間件方法的執行順序:

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

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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        # print(callback, callback_args, callback_kwargs) #<function test at 0x7fd39b986040> () {}
        print('m1.process_view')
        # response = callback(request, *callback_args, **callback_kwargs)
        # return response
    #
    def process_response(self, request, response):
        print('m1.process_response')
        return response

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

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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print('m2.process_view')

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

    def process_exception(self, request, exception):
        # print('m2.process_exception')
        return HttpResponse('出現異常!')

"""
m1.process_request
m2.process_request
m1.process_view
m2.process_view
test
m2.process_response
m1.process_response
"""

異常被M2的process_exception處理了,跳過M1的process_exception,直接執行process_response。頁面也不沒有報錯了:
在這裏插入圖片描述
中間件中還有process_template_response方法,但是這個方法在視圖函數的返回值中有render方法纔會執行,沒有render方法不會被執行,所以這裏修改視圖函數:

class Foo:
    def __init__(self, req):
        self.req = req

    def render(self):
        return HttpResponse()

def test(request):
    obj = Foo(request)
    return obj

接下來可以看到process_template_response方法被執行,

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

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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print('m1.process_view')

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

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

    def process_template_response(self, request, response):
        """
        視圖函數的返回值中有render方法纔會執行
        :param request:
        :param response:
        :return:
        """
        print('m1.process_template_response')
        return response

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

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print('m2.process_view')

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

    def process_exception(self, request, exception):
        return HttpResponse('出現異常!')

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

"""
m1.process_request
m2.process_request
m1.process_view
m2.process_view
m2.process_template_response
m1.process_template_response
m2.process_response
m1.process_response
"""

process_template_response方法的使用,可以幫助我們把一些可以複用的功能組件拆分出來,如JSON序列化:

class Foo:
    def __init__(self, req, status, msg):
        self.req = req
        self.status = status
        self.msg = msg

    def render(self):
        import json
        ret = {
            'status': self.status,
            'msg': self.msg
        }
        return HttpResponse(json.dumps(ret))

def test(request):
    return Foo(request, True, '錯誤信息!')

在視圖函數中打造功能,改造另外一個對象,讓這個對象把我們的數據封裝起來:

class JsonResponse:
    """
    內部幫助我們序列化,
    """
    def __init__(self, req, status, msg):
        self.req = req
        self.status = status
        self.msg = msg

    def render(self):
        import json
        ret = {
            'status': self.status,
            'msg': self.msg
        }
        return HttpResponse(json.dumps(ret))


def test(request):
    return JsonResponse(request, True, '錯誤信息!')

視圖函數返回的對象且對象中有render方法纔會執行process_template_response方法。

3. 中間件的應用

中間件可以對 所有請求或一部分請求做批量處理。使用緩存時,需要對 所有請求進行判斷,緩存中如果有就把緩存中的數據返回,沒有就執行視圖函數。對所有的請求進行判斷就需要使用到中間件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章