65 Django -- 中间件

目录

  • 中间件

    • 中间件介绍
    • Django生命周期--终版
    • 自定义中间件
      • 基于自定义中间件进行session用户认证
    • 中间件执行顺序
      • process_request
      • process_response
      • process_view
      • process_exception
      • process_template_response
      • 自定义中间件总体程序

中间件

注: 中间件中的大多数方法在返回None时表示会进入下一项事件,当返HttpResponese对象时表示此请求结果,直接返回给客户端。

中间件介绍

中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。

如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。

直白一点:中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

setting.py中MIDDLEWARE配置项,就是diango默认自带的中间件。

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',
]

# 列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。

Django生命周期--终版

自定义中间件

中间件可以定义五个方法,分别是:(主要的是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)

  以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

? 当用户发起请求的时候会依次从上到下经过所有的的中间件,这个时候的请求是process_request,最后到达views的函数中,views函数处理后,再依次按倒序穿过中间件,这个时候是process_response,最后返回给请求者。

示例:

  1. 在app01下新建一个文件夹,如 middlewares
  2. 在文件夹下新建一个mymiddleware.py文件
  3. 在py文件下创建中间件
    from django.utils.deprecation import MiddlewareMixin
    
    class LoginAuth(MiddlewareMixin):
    
     def process_request(self, request):
    
         print('请求来了!')
    
     def process_response(self, request, response):
    
         print('响应要走了!')
    
         return response     # 必须返回response对象,不然上层的中间件就没有拿到httpresponse对象,就会报错
  4. setting.py中MIDDLEWARE配置项中配置路径
    'app01.middlewares.mymiddleware.LoginAuth',

基于自定义中间件进行session用户认证

如果用户没有登录,只能访问登录页面,不能访问其他页面,访问会跳转到登录页面。

自定义中间件.

from django.utils.deprecation import MiddlewareMixin

from django.shortcuts import render,HttpResponse, redirect

white_list = ['/login/',]   # 白名单,将登录页面的路径放入

class LoginAuth(MiddlewareMixin):

    def process_request(self, request):
        print('请求来了!')
        status = request.session.get('status')  # 获取设置的session值
        path = request.path     # 获取访问路径
        if path not in white_list:
            # 如果访问路径不在白名单中
            if not status:
                # 如果没有session的值,直接响应浏览器,让其跳转到login登录页面。不会到达视图函数。
                return redirect('login')

         # else:
           # return None        # 可不写,表示请求可以往下走,到达视图函数。

views.py

def login(request):

    if request.method == 'GET':

        return render(request, 'login.html')

    else:
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        print(user)
        if user == 'yan' and pwd == '123':
            request.session['status'] = True    # 登陆成功后,设置session,
            return HttpResponse('1')
        else:
            return HttpResponse('0')

login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>

<div style="width: 500px;height:200px;background-color: #4ba7ff;margin-top: 180px; margin-left: 350px;">
    <div style="padding-top:50px;">
        {% csrf_token %}
    <div class="form-group">
        <label class="col-sm-2 control-label">用户名</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" placeholder="请输入用户名" id="username">
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-2 control-label">密码</label>
        <div class="col-sm-10">
            <input type="password" class="form-control" placeholder="请输入密码" id="password">
        </div>
    </div>

    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default" id="sub">登 录</button>
            <span id="error" style="color: red"></span>
        </div>
    </div>
    </div>
</div>
</body>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>

<script >
    // 登录绑定点击事件
    $('#sub').click(function () {

        var username=$('#username').val();
        var password=$('#password').val();

        // csrf方式一:
        {#var csrf=$('[name=csrfmiddlewaretoken]').val();#}
        // csrf方式二:
        var csrf = '{{ csrf_token }}';
        $.ajax({

            url:'{% url "login" %}',
            type:'post',
            data:{'user':username,'pwd':password, "csrfmiddlewaretoken":csrf},      // data会携带数据

            success:function (res) {
                if(res === '1'){
                    location.href='{% url "home" %}';
                    {#$('#error').text('登录成功!'); }#}
                    }
                else{
                    {#console.log(res);#}
                    $('#error').text('用户名或密码错误!')
                }
            }
        })
    })
</script>
</html>

中间件执行顺序

process_request

  process_request有一个参数,就是request,这个request和视图函数中的request是一样的。

  它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。

process_response

  它有两个参数,一个是request,一个是response,request就是上述一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。

自定义中间件 mymiddleware.py

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_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

在浏览器中访问 /login/ 路径: 会访问到login页面

打印的结果

# 打印结果:

MD1--process_request
MD2--process_request
这是login函数!
MD2--process_response
MD1--process_response

流程图如下:

如果将上面的MD2类中的process_request方法添加 return HttpResponse(‘MD2中断’):

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse, redirect

class MD2(MiddlewareMixin):

    def process_request(self, request):
        print('MD2--process_request')

        return HttpResponse('MD2中断')

    def process_response(self, request, response):
        print('MD2--process_response')

        return response

再访问login路径: 会发现页面显示 :MD2中断

打印的结果:

# 打印的结果:

MD1--process_request
MD2--process_request
MD2--process_response
MD1--process_response

发现不会执行视图函数,会直接响应给浏览器 MD2中断。

流程图如下:

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并返回响应结果。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse, redirect

class MD1(MiddlewareMixin):

    def process_request(self, request):
        print('MD1--process_request')

        # return HttpResponse('MD1中断')

    def process_response(self, request, response):
        print('MD1--process_response')

        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 50)
        print("MD1 中的process_view")
        print(view_func, view_func.__name__)
        # 就是url映射到的那个视图函数,也就是说每个中间件的这个process_view已经提前拿到了要执行的那个视图函数
        # ret = view_func(request) #提前执行视图函数,不用到了上图的试图函数的位置再执行,如果你视图函数有参数的话,可以这么写 view_func(request,view_args,view_kwargs)
        # return ret  #直接就在MD1中间件这里这个类的process_response给返回了,就不会去找到视图函数里面的这个函数去执行了。

class MD2(MiddlewareMixin):

    def process_request(self, request):
        print('MD2--process_request')

        # return HttpResponse('MD2中断')

    def process_response(self, request, response):
        print('MD2--process_response')

        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 50)
        print("MD2 中的process_view")
        print(view_func, view_func.__name__)

打印的结果:

MD1--process_request
MD2--process_request
--------------------------------------------------
MD1 中的process_view
<function login at 0x00000253A7125C80> login
--------------------------------------------------
MD2 中的process_view
<function login at 0x00000253A7125C80> login

这是login函数!
MD2--process_response
MD1--process_response

流程图如下:

  1. 如果在 MD1中 process_view写入:
ret = view_func(request)
return ret

打印结果:

MD1--process_request
MD2--process_request
--------------------------------------------------
MD1 中的process_view
<function login at 0x00000214CD665C80> login
这是login函数!
MD2--process_response
MD1--process_response

流程图如下:

  1. 如果在 MD1中 process_view写入:

    return HttpResponse('MD1--view 中断!')

    则结果不会到达视图函数,会直接执行MD2的 process_response.

执行结果:

MD1--process_request
MD2--process_request
--------------------------------------------------
MD1 中的process_view
<function login at 0x000001CFD0705C80> login
MD2--process_response
MD1--process_response

流程图如下:

process_exception

  process_exception(self, request, exception)

该方法两个参数:

  一个HttpRequest对象

  一个exception是视图函数异常产生的Exception对象。

  这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。

如果视图函数中无异常,process_exception方法不执行。

在视图函数中的login函数中添加主动错误:

raise ValueError('主动错误!')

在MD1和MD2中添加:

    def process_exception(self, request, exception):
        print(exception)
        print("MD1 -- process_exception")
        # print("MD2 -- process_exception")

打印结果:

MD1--process_request
MD2--process_request
--------------------------------------------------
MD1 中的process_view
<function login at 0x000002116CA45C80> login
--------------------------------------------------
MD2 中的process_view
<function login at 0x000002116CA45C80> login

这是login函数!

主动错误!
MD2 -- process_exception

主动错误!
MD1 -- process_exception

MD2--process_response
MD1--process_response

流程图如下:

如果在MD2中的process_exception添加返回值,是一个HttpResponse对象。

不会执行MD1的process_exception,响应页面是 MD2--exception 中断!。

 def process_exception(self, request, exception):
        print(exception)
        print("MD2 -- process_exception")

        return HttpResponse('MD2--exception 中断!')

打印结果:

MD1--process_request
MD2--process_request
--------------------------------------------------
MD1 中的process_view
<function login at 0x0000018EA1C15C80> login
--------------------------------------------------
MD2 中的process_view
<function login at 0x0000018EA1C15C80> login

这是login函数!

主动错误!
MD2 -- process_exception

MD2--process_response
MD1--process_response

流程图如下:

process_template_response

process_template_response(self, request, response)

  它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

  process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。

在视图刚好执行之后被调用,在每个请求上调用,返回实现了render方法的响应对象。

 def process_template_response(self, request, response):
        print("MD1 -- process_template_response")
        # print("MD2 -- process_template_response")
        return response
def index(request):
    print("这是index函数!")
  #raise ValueError('主动错误!')
    def render():
        print("in index--render")
        #raise ValueError('出错啦!') #至于render函数中报错了,那么会先执行process_template_response方法,然后执行process_exception方法,如果是在render方法外面报错了,那么就不会执行这个process_template_response方法了。

        return HttpResponse("这是index的render!") #返回的将是这个新的对象
    rep = HttpResponse("OK")
    rep.render = render
    return rep      # 不会返回这个

打印结果:

MD1--process_request
MD2--process_request
--------------------------------------------------
MD1 中的process_view
<function index at 0x000002011A1072F0> index
--------------------------------------------------
MD2 中的process_view
<function index at 0x000002011A1072F0> index

这是index函数!
MD2 -- process_template_response
MD1 -- process_template_response
in login--render

MD2--process_response
MD1--process_response

? 结果分析:视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD2的,在执行MD1的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。

流程图如下:

如果render方法错误,流程图:

总体大致的程序流程图如下所示:

自定义中间件总体程序

# -*- coding:utf-8 -*-
"""
@file   : mymiddleware.py
@Author : Python
@Date   : 2019/10/11 16:05
"""

from django.utils.deprecation import MiddlewareMixin

from django.shortcuts import render,HttpResponse, redirect
#
# white_list = ['/login/']

# class LoginAuth(MiddlewareMixin):
#       """登录认证"""
#
#     def process_request(self, request):
#         print('请求来了!')
#         status = request.session.get('status')
#         path = request.path
#         if path not in white_list:
#             if not status:
#                 return redirect('login')
#
#
#     def process_response(self, request, response):
#
#         print('响应要走了!')
#
#         return response

class MD1(MiddlewareMixin):

    def process_request(self, request):
        print('MD1--process_request')

        # return HttpResponse('MD1中断')

    def process_response(self, request, response):
        print('MD1--process_response')

        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 50)
        print("MD1 中的process_view")
        print(view_func, view_func.__name__)
        # 就是url映射到的那个视图函数,也就是说每个中间件的这个process_view已经提前拿到了要执行的那个视图函数
        # ret = view_func(request) #提前执行视图函数,不用到了上图的试图函数的位置再执行,如果你视图函数有参数的话,可以这么写 view_func(request,view_args,view_kwargs)
        # return ret  #直接就在MD1中间件这里这个类的process_response给返回了,就不会去找到视图函数里面的这个函数去执行了。
        # ret = view_func(request)
        # return ret

        # return HttpResponse('MD1--view 中断!')

    def process_exception(self, request, exception):
        print(exception)
        print("MD1 -- process_exception")

        # return HttpResponse('MD1--exception 中断!')

    def process_template_response(self, request, response):
        print("MD1 -- process_template_response")
        return response

class MD2(MiddlewareMixin):

    def process_request(self, request):
        print('MD2--process_request')

        # return HttpResponse('MD2中断')

    def process_response(self, request, response):
        print('MD2--process_response')

        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 50)
        print("MD2 中的process_view")
        print(view_func, view_func.__name__)

        # ret = view_func(request)
        # return ret

    def process_exception(self, request, exception):
        print(exception)
        print("MD2 -- process_exception")

        # return HttpResponse('MD2--exception 中断!')

    def process_template_response(self, request, response):
        print("MD2 -- process_template_response")
        return response

原文地址:https://www.cnblogs.com/yzm1017/p/11674533.html

时间: 2024-11-05 16:52:27

65 Django -- 中间件的相关文章

关于Django中间件自己的一点理解

Django中间件我觉得是一个非常重要的东西,所以把自己的一些理解分享出来,哪里有不对的还希望大家可以帮助我修改. 因为是自己写的代码,所以就把代码粘过来了,里边每一部分都会有自己的理解和注释,见谅! from django.utils.deprecation import MiddlewareMixinfrom django.shortcuts import redirect,HttpResponse #对于有些Django没有MiddleMixin类,就在上边自己写一个,但是这时上边的类引用

Django中间件 及 form 实现用户登陆

Django中间件 及 form 实现用户登陆 Form 验证 密码调用md5 加密存储 form.add_error("字段名", "错误信息") 自定义错误信息 装饰器实现 用户认证 中间件实现 用户认证 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影响到性能. django默认的中间件在settings.py中 当用户发起请求

Django 中间件简介

Django 中间件简介 django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法. 在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件 中间件中一共有四个方法: process_request(self,request) 发送请求 process_view(self, request, callback,

【python】-- Django 中间件、缓存、信号

Django  中间件.缓存.信号 一. Django  中间件 django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法. 在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件: MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', '

Django学习之七:Django 中间件

目录 Django 中间件 自定义中间件 - - - 大体两种方式 将中间件移除 实例 总结 Django 中间件 Django中间件可看作是包裹在django处理机制的外层,Httprequest和Httpresponse都要经中间件处理,从而起到全局钩子的作用,可以达到一些目的:如过滤请求,预处理请求,响应修改等. 我理解,很多基于会话的应用系统,都可以设计中间件环节.如数据库系统.中间件可以起到全局钩子的作用.django的中间件的设计就是一种递归顺序调用,利用httprequest作为递

利用django中间件CsrfViewMiddleware防止csrf攻击

一.在django后台处理 1.将django的setting中的加入django.contrib.messages.middleware.MessageMiddleware,一般新建的django项目中会自带的. MIDDLEWARE_CLASSES = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middle

Django中间件的使用

Django中间件的使用 中间件(middleware) 中间件应用于request与服务端之间和服务端与response之间,客户端发起请求到服务端接收可以通过中间件,服务端返回响应与客户端接收响应可以通过中间件,也就是说中间件可以处理request和response. Django默认的中间件 在settings中Django以及默认添加了许多有用的中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'dja

☆Django☆---中间件 csrf跨站请求伪造 auth模块 settings功能插拔式源码

Django中间件 django生命周期图 中间件: 概念: Django中间件就类似于 django的保安   请求 的时候需要先经过中间件才能到达django后端(urls, views)   响应 走的时候也需要经过中间件才能到达web服务网关接口 django默认的七个中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.Session

Django中间件、csrf跨站请求伪造以及基于Django中间件思想实现功能的插拔式配置

一.django中间件 1.1解释:django中间件是类似于是django的保安,请求的时候需要先经过中间件才能到达django后端(urls,views,templates,models),响应走的时候也需要经过中间件才能到达web服务网关接口 1.2django默认的七个中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.Session