Django 中间件详解

Django 中间件

一、请求生命周期:

以下图是客户端发起一次http请求的流程:
在这里插入图片描述
注意:django框架不包括socket,要借助图中两个模块实现socket,进行客户端和服务器通信。wsgi性能较弱,一般测试开发用;企业中用uwsgi比较好,性能强,并发好

二、中间件简介:

上图可知,在请求到达视图之前,会依次执行中间件,视图返回的响应,依次倒序执行中间件

django 中间件(middleware),在django中其实就是一个,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

在django项目的setting.py文件中,有一个MIDDLEWARE列表,其中每一个元素都是一个中间件

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'qinspect.middleware.QueryInspectMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

若需要对请求作统一处理,比如执行,验证登录、日志记录、获取CBV响应时间,我们可以使用装饰器,但是很麻烦,每个视图都要手动加装饰器,这时使用中间件会更方便。

三、中间件应用:

1.做IP限制:

  • 放在中间件类的列表中,阻止某些IP访问

2.URL访问过滤:

  • 如果用户访问的是login视图(直接pass)
  • 如果访问的其他视图(需要检测是不是有session已经存在,那么pass,没有返回login进行登录)

3.缓存:

  • 客户端请求来了,中间件去缓存查看是否有数据,若有直接返回给客户端,没有再去逻辑层执行视图函数

四、自定义中间件:

下面我们自定义一个中间件,获取每个接口响应时间:

#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function

import time
from django.utils.deprecation import MiddlewareMixin
from libs.api_tools import slow_api_utils


class CustomizeMiddleware(MiddlewareMixin):
    """自定义中间件: 获取所有接口的处理时间."""

    def process_request(self, request):
		# 获取这个请求的开始时间
        self.start_time = time.time()

    def process_response(self, request, response):        
        end_time = time.time()
        # 结束时间 - request 开始时间  = 接口的处理时间
        process_time = end_time - self.start_time
	   # 下面是处理process_time 时间发起异步请求, 这里省略......
        slow_api_utils.judge_max_process_time(request, process_time)
        return response

在setting.py中注册中间件:

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'qinspect.middleware.QueryInspectMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'libs.api_tools.middleware.CustomizeMiddleware'  # 创建的自定义中间件类(路径 + 类名)
]

注意:django 1.10之后django无法导入,因此直接把MiddlewareMixin类拿过来继承就好了:

class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response


class CustomizeMiddleware(MiddlewareMixin):  # 自定义类,继承MiddlewareMixin
    ......

同样也是在setting.py中注册中间件:

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'qinspect.middleware.QueryInspectMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'libs.api_tools.middleware.CustomizeMiddleware'  # 创建的自定义中间件类(路径 + 类名)
]

五、中间件五个方法:

process_request 请求进来时执行;

  • 不能有返回值,若在process_request有返回值,那么下面的中间件将不会执行,后面的URL以及视图函数也不会执行,直接执行当前的中间件的process_response方法。

    # 请求时,仅让IP192.168.1.1才可以进行访问
    from django.shortcuts import HttpResponse
    class CustomizeMiddleware(MiddlewareMixin):
    
        def process_request(self, request, response):
            allowed_ip = ['192.168.1.1',]
            # 允许/禁止访问的ip地址列表,判断请求ip, 放行/阻拦
            if request.META.get('REMOTE_ADDR') not in allowed_ip:
                return HttpResponse('您的IP地址无权访问')
            else:
                return None
    
        def process_response(self, request, response):
            return response
    

process_response 返回响应时执行;

  • 默认情况下返回response, 即视图函数的返回值,如果在这个方法中自定义了返回值,将返回自定义返回值。

    class CustomizeMiddleware(MiddlewareMixin):
    
        def process_response(self, request, response):
            print('处理一些逻辑条件等......')
            return response
    

process_view 视图函数;

  • 执行过程:

    执行完process_request  →  路由分发(dispatch)  →  process_view  →  视图函数  → process_response
    
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class CustomizeMiddleware1(MiddlewareMixin):
        def process_request(self,request):
            print("...来自中间件1的请求...")
        def process_response(self,request,response):
            print("...来自中间件1的返回...")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("...中间件1view...")
    
    class CustomizeMiddleware2(MiddlewareMixin):
        def process_request(self,request):
            print("...来自中间件2的请求...")
        def process_response(self,request,response):
            print("...来自中间件2的返回...")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("...中间件2view...")
    
    class CustomizeMiddleware3(MiddlewareMixin):
        def process_request(self,request):
            print("...来自中间件3的请求...")
        def process_response(self,request,response):
            print("...来自中间件2的返回...")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("...中间件3view...")
    
    # 输出结果为:
    ...来自中间件1的请求..
    ...来自中间件2的请求..
    ...来自中间件3的请求..
    ...中间件1view...
    ...中间件2view...
    ...中间件3view...
    ...来自中间件3的返回...
    ...来自中间件2的返回...
    ...来自中间件1的返回...
    

    如图所示:
    在这里插入图片描述

  • 当最后一个中间的process_request到达路由关系映射之后,返回到中间件1的process_view,然后依次往下,到达views函数,最后通过process_response依次返回到达用户。

process_exception 视图中出现异常,就会被执行(默认不执行);

# 定义一个提示错误信息页面
from django.shortcuts import HttpResponse

class CustomizeMiddleware(MiddlewareMixin):

    def process_exception(self, request, exception):
        return HttpResponse('在处理中间件时,抛出了异常,就会走这里哦~')

process_template_response 若返回的对象有render方法,就会被执行(默认不执行);

process_template_response(self, request, response)
  • 它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)
  • process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)
  • 视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行CustomizeMiddleware3的,再执行CustomizeMiddleware2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。

猜你喜欢

转载自blog.csdn.net/Fe_cow/article/details/91344472
今日推荐