zoukankan      html  css  js  c++  java
  • Django 中间件

    要点概论:

    1. 中间件介绍

    2. 中间件的执行流程

    3. 自定义中间件

    4. 中间件版登录验证

    1. 中间件介绍

      官方说法:中间件时一个用来处理Django的请求和响应的框架级别的钩子。

      它是一个轻量,低级别的插件系统,用于在全局范围内改变 Django 的出入和输出。

      每个中间件组件都负责做一些特定的功能。

      打开Django项目的 Setting.py 文件,可以看到 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配置项是一个列表,列表中的字符串其实是一个个类,也就是一个个中间件。

    2. 中间件的执行流程

      首先来看一下 Django 框架的请求流程图,了解一下中间件在请求流程中的作用:

      即在socket和路由系统之前,每次进行request(输入)和response(输出)的时候都要经过中间件。

      请求到达中间件之后,先按照正序执行每个注册中间件的 process_reques方法,如果返回None,

      就依次执行后续中间件,如果返回HttpResponse对象,就不再执行后面的process_request方法,

      而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。

      如下图所示:

    process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。加入中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行:

    process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

    3. 自定义中间件

      中间件可以定义五个方法(其中主要的是process_request和process_response):

      •   process_request(self,request)
      •   process_view(self, request, view_func, view_args, view_kwargs)
      •   process_template_response(self,request,response)
      •   process_exception(self, request, exception)
      •   process_response(self, request, response)

      以上方法的返回值可以hi是None或一个HttpResponse对象,如果是None,则继续按照django流程

      执行后续中间件,如果是HttpResponse对象,则直接将该对象返回给用户。

    class MD1(MiddlewareMixin):
        # 处理请求的方法
        def process_request(self,request):
            print('这是中间件1号的请求')
            print('中间件1号请求的内存地址【{}】'.format(id(request)))
            
            request.one = '1号请求设置的属性'
            
        # 处理响应的方法
        def process_response(self,request,response):
            print('中间件1号里面的处理响应方法')
            return response
        
        
        # 中间件处理视图的方法
        def process_view(self, request, view_func, view_args, view_kwargs):
            '''
            :param request: 请求对象
            :param view_func:  将要执行的视图函数
            :param view_args:  将要执行的视图函数的位置参数
            :param view_kwargs:  将要执行的视图函数的关键字参数
            :return: 
            '''
        
            print('中间件1号的视图方法')
        
        # 中间件处理异常的方法
        def process_exception(self,request,exception):
            print('中间件一号的异常处理方法')
            
        # 中间件中处理模板响应
        def process_template_response(self, request, response):
            print("中间件1号中的模板响应方法")
            return response
        
    
    class MD2(MiddlewareMixin):
        # 处理请求方法
        def process_request(self, request):
            print("这是中间件2号里面的请求方法")
            print('中间件2号的请求内存地址【{}】'.format(id(request)))
            print(request.one)
            
        # 处理响应方法
        def process_response(self, request, response):
            print("中间件2号里面的处理响应方法")
            return response
    
        # 处理视图方法
        def process_view(self, request, view_func, view_args, view_kwargs):
            """
            :param request: 请求对象
            :param view_func: 将要执行的视图函数
            :param view_args: 将要执行的视图函数的位置参数
            :param view_kwargs: 将要执行的视图函数的关键字参数
            :return:
            """
            print("中间件2号中的处理视图方法")
            # print(type(view_func))
            # print(view_func.__doc__)
            # print(view_func.__name__)
        
        # 处理异常方法
        def process_exception(self, request, exception):
            """
            中间件中处理异常的方法
            :param request:
            :param exception: 视图函数中抛出的异常
            :return:
            """
            print("*" * 120)
            print(exception)
            print("*" * 120)
            print("中间件2号中的处理异常方法")
      
        # 处理模板响应
        def process_template_response(self, request, response):
            print("中间件2号中的处理模板响应")
            return response
    自定义中间件示例
    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',
        'middlewares.MD1',  # 自定义中间件MD1
        'middlewares.MD2'  # 自定义中间件MD2
    ]
    配置项中注册中间件
    这是中间件1号的请求
    [10/Apr/2018 17:13:31] "GET /index/ HTTP/1.1" 200 21
    中间件1号请求的内存地址【1261599124112】
    这是中间件2号里面的请求方法
    中间件2号的请求内存地址【1261599124112】
    1号请求设置的属性
    中间件1号的视图方法
    中间件2号中的处理视图方法
    中间件2号里面的处理响应方法
    中间件1号里面的处理响应方法
    访问视图时中间件执行顺序

       总结:

      1)中间件的process_request方法是在执行视图函数之前执行的。

      2)当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。

      3)不同中间件之间传递的request都是同一个对象

      多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,

      也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,

      最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

     

     4. 中间件版登录验证

    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        url(r'^index/$', views.index),
        url(r'^login/$', views.login, name='login'),
    ]
    urls.py
    from django.shortcuts import render, HttpResponse, redirect
    
    
    def index(request):
        return HttpResponse('this is index')
    
    
    def home(request):
        return HttpResponse('this is home')
    
    
    def login(request):
        if request.method == "POST":
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
    
            if user == "Q1mi" and pwd == "123456":
                # 设置session
                request.session["user"] = user
                # 获取跳到登陆页面之前的URL
                next_url = request.GET.get("next")
                # 如果有,就跳转回登陆之前的URL
                if next_url:
                    return redirect(next_url)
                # 否则默认跳转到index页面
                else:
                    return redirect("/index/")
        return render(request, "login.html")
    views.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>登录页面</title>
    </head>
    <body>
    <form action="{% url 'login' %}">
        <p>
            <label for="user">用户名:</label>
            <input type="text" name="user" id="user">
        </p>
        <p>
            <label for="pwd">密 码:</label>
            <input type="text" name="pwd" id="pwd">
        </p>
        <input type="submit" value="登录">
    </form>
    </body>
    </html>
    login.html
    lass AuthMD(MiddlewareMixin):
        white_list = ['/login/', ]  # 白名单
        balck_list = ['/black/', ]  # 黑名单
    
        def process_request(self, request):
            from django.shortcuts import redirect, HttpResponse
    
            next_url = request.path_info
            print(request.path_info, request.get_full_path())
    
            if next_url in self.white_list or request.session.get("user"):
                return
            elif next_url in self.balck_list:
                return HttpResponse('This is an illegal URL')
            else:
                return redirect("/login/?next={}".format(next_url))
    middlewares.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',
        'middlewares.AuthMD',
    ]
    在settings.py中注册

    AuthMD中间件注册后,所有的请求都要走AuthMD的process_request方法。

    访问的URL在白名单内或者session中有user用户名,则不做阻拦走正常流程;

    如果URL在黑名单中,则返回This is an illegal URL的字符串;

    正常的URL但是需要登录后访问,让浏览器跳转到登录页面。

    注:AuthMD中间件中需要session,所以AuthMD注册的位置要在session中间的下方。

      

  • 相关阅读:
    php Date()函数输出中文年月日时分秒
    jQuery动态添加删除与添加表行代码
    sql随机查询数据语句(NewID(),Rnd,Rand(),random())
    asp.net 逻辑操作符与(&&),或(||),非(!)
    php static 变量的例子
    asp.net C# int 类型在32/64位环境下取值范围无变化
    js保留小数点后N位的方法介绍
    [Java] LinkedHashMap 源码简要分析
    [Java] HashMap 源码简要分析
    [Java] Hashtable 源码简要分析
  • 原文地址:https://www.cnblogs.com/HZY258/p/8779868.html
Copyright © 2011-2022 走看看