一.中间件的介绍 

  中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,

并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,

用不好会影响到性能

  1. Django 的请求生命周期

  2.Django默认自带的一些中间件

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

  3.执行中间件的过程

二. 自定义中间件

  1.在项目中创建一个包

  在项目中创建一个包,随便起名字,一般都放在一个叫做utils的包里面,

表示一个公用的组件,创建一个py文件,随便起名字,

例如叫做:middlewares.py,内容如下
from django.utils.deprecation import MiddlewareMixin

class MD1(MiddlewareMixin):
    #自定义中间件,不是必须要有下面这两个方法,有request方法说明请求来了要处理,有response方法说明响应出去时需要处理,不是非要写这两个方法,如果你没写process_response方法,那么会一层一层的往上找,哪个中间件有process_response方法就将返回对象给哪个中间件
    def process_request(self, request):
        print("MD1里面的 process_request")

    def process_response(self, request, response):
        print("MD1里面的 process_response")
        return response

  2.在 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',
    'utils.middlewares.MD1',  # 自定义中间件MD1,这个写的是你项目路径下的一个路径,                例如,如果你放在项目下,文件夹名成为utils,                那么这里应该写utils.middlewares.MD1
    'utils.middlewares.MD2'  # 自定义中间件MD2
]

三.常用方法

  1. process_request

process_request有一个参数,就是request,这个request和

    视图函数中的request是一样的。

它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,

    按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,

    Django将不执行视图函数,而将相应对象返回给浏览器。
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")
        pass

  ①在注册时 先注册 MD1 再注册 MD2,打印结果为:

MD1里面的 process_request
MD2里面的 process_request
app01 中的 index视图

  ②在注册时 先注册MD2 再注册 MD1,打印结果为:

MD2里面的 process_request
MD1里面的 process_request
app01 中的 index视图
注:   多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,

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

方法最后执行,最后一个中间件的process_request方法最后一个执行,

它的process_response方法是最先执行。

  2. process_response

  它有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,

response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。

  ①示例1:

from django.utils.deprecation import MiddlewareMixin

class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1里面的 process_request")
        #不必须写return值
    def process_response(self, request, response):#request和response两个参数必须有,名字随便取
        print("MD1里面的 process_response")
        #print(response.__dict__['_container'][0].decode('utf-8')) #查看响应体里面的内容的方法
     return response  #必须有返回值,写return response  ,这个response就像一个接力棒一样
        #return HttpResponse('瞎搞') ,如果你写了这个,那么你视图返回过来的内容就被它给替代了

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2里面的 process_request")
        pass

    def process_response(self, request, response): #request和response两个参数必须要有,名字随便取
        print("MD2里面的 process_response")
        return response  #必须返回response,不然你上层的中间件就没有拿到httpresponse对象,就会报错

  结果:

MD2里面的 process_request
MD1里面的 process_request
app01 中的 index视图
MD1里面的 process_response
MD2里面的 process_response
看结果可知:

      process_response方法是在视图函数之后执行的,并且顺序是MD1比MD2先执行。

(此时settings.py中 MD2比MD1先注册)

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

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

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

  ②示例2:

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

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")     return HttpResponse("Md2中断")
     #process_request方法里面不写返回值,默认也是返回None,如果你自己写了return None,      也是一样的效果,不会中断你的请求,但是如果你return 的一个httpresponse对象,      那么就会在这个方法中断你的请求,直接返回给用户,这就成了非正常的流程了
        #并且,如果你在这里return了httpresponse对象,那么会从你这个中间件类中的      process_response方法开始执行返回操作,所以这个类里面只要有process_response方法,      肯定会执行

    def process_response(self,request,response):
        print("Md1返回")
        return response

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
        
    def process_response(self,request,response):
        print("Md2返回")
        return response

  结果为:

Md1请求
Md1返回

  流程图如下:

    实例: 访问白名单设置

class M1(MiddlewareMixin):

    def process_request(self,request):

        #设置路径白名单,只要访问的是login登陆路径,就不做这个cookie认证
        if request.path not in [reverse('login'),]:
            print('我是M1中间件') #客户端IP地址
            # return HttpResponse('sorry,没有通过我的M1中间件')
            is_login = request.COOKIES.get('is_login', False)

            if is_login:
                pass
            else:
                # return render(request,'login.html')
                return redirect(reverse('login'))
        else:
            return None #别忘了return None

    def process_response(self,request,response):

        print('M1响应部分')
        # print(response.__dict__['_container'][0].decode('utf-8'))
        return response
        # return HttpResponse('瞎搞')

  3. 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_request方法之后)调用process_view方法。

  ① 流程图

  ② 示例:(访问index视图函数)

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

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        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")
        pass

    def process_response(self, request, response):
        print("MD2里面的 process_response")
        return response

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

  结果:

MD1里面的 process_request
MD2里面的 process_request
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x000001DE68317488> index
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x000001DE68317488> index
app01 中的 index视图
MD2里面的 process_response
MD1里面的 process_response

  ③写了返回对象的情况

返回值是HttpResponse:

            当前中间件之后的中间的process_view方法和视图函数都不执行,直接执行最后一个中间件的process_reponse方法.

  4.process_exception

process_exception(self, request, exception)

      该方法两个参数:

      一个HttpRequest对象

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

      这个方法只有在视图函数中出现异常了才执行,

它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,

Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。

如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。

它的执行顺序也是按照中间件注册顺序的倒序执行。

  ①示例1:

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

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

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

class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2里面的 process_request")
        pass

    def process_response(self, request, response):
        print("MD2里面的 process_response")
        return response

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

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

  在视图函数中抛出一个异常

def index(request):
    print("app01 中的 index视图")
    raise ValueError("呵呵")
    return HttpResponse("O98K")

  流程图:

  ②示例2:在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("-" * 80)
        print("MD2 中的process_view")
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(exception)
        print("MD2 中的process_exception")
        return HttpResponse(str(exception))  # 返回一个响应对象

  结果:

MD1里面的 process_request
MD2里面的 process_request
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x0000022C09727488> index
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x0000022C09727488> index
app01 中的 index视图
呵呵
MD2 中的process_exception
MD2里面的 process_response
MD1里面的 process_response

  流程图:

返回None:

    正常流程.

返回HttpResponse对象:

    后面的中间件的process_view方法不执行,直接执行最后一个中间件的process_response方法.

process_template_response(用的比较少)

process_template_response(self, request, response)

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

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

class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1里面的 process_request")

    def process_response(self, request, response):
        print("MD1里面的 process_response")
        return response

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

    def process_exception(self, request, exception):
        print(exception)
        print("MD1 中的process_exception")
        return HttpResponse(str(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")

    def process_response(self, request, response):
        print("MD2里面的 process_response")
        return response

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

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

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

views.py中:

def index(request):
    print("app01 中的 index视图")

    def render():
        print("in index/render")
        return HttpResponse("O98K")
    rep = HttpResponse("OK")
    rep.render = render
    return rep

访问index视图,终端输出的结果:

MD2里面的 process_request
MD1里面的 process_request
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x000001C111B97488> index
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x000001C111B97488> index
app01 中的 index视图
MD1 中的process_template_response
MD2 中的process_template_response
in index/render
MD1里面的 process_response
MD2里面的 process_response

从结果看出:

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

补充:  登录时浏览器自动加  "/"

  ①在输入时

  ②浏览器自动加 '/'

  ③在一些情况下不需要加时,

在settings.py文件中进行设置

day62 中间件的更多相关文章

  1. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  2. ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”

    DeveloperExceptionPageMiddleware中间件利用呈现出来的错误页面实现抛出异常和当前请求的详细信息以辅助开发人员更好地进行纠错诊断工作,而ExceptionHandlerMi ...

  3. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  4. ASP.NET Core 中间件之压缩、缓存

    前言 今天给大家介绍一下在 ASP.NET Core 日常开发中用的比较多的两个中间件,它们都是出自于微软的 ASP.NET 团队,他们分别是 Microsoft.AspNetCore.Respons ...

  5. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

  6. .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类

    .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...

  7. .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理

    .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...

  8. 从中间件的历史来看移动App开发的未来

    在移动开发领域我们发现一个很奇怪的现象:普通菜鸟新手经过3个月的培训就可以拿到 8K 甚至上万的工作:在北京稍微有点工作经验的 iOS 开发,就要求 2 万一个月的工资.不知道大家是否想过:移动应用开 ...

  9. ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件

    虽然ASP.NET Core应用的路由是通过RouterMiddleware这个中间件来完成的,但是具体的路由解析功能都落在指定的Router对象上,不过我们依然有必要以代码实现的角度来介绍一下这个中 ...

随机推荐

  1. Linux 使用硬盘

    一.硬盘分区规划: swap(交换,掉期交易,互换)分区:虚拟内存使用,不能保存用户信息. boot(引导)分区:保存启动系统得相关文件. root(根)分区:放置系统文件得根,所有文件都保存在该分区 ...

  2. nginx配置支持http2

    1.简介 nginx 配置支持http2.目前大多数网站都是http1.1(如果你没有特别配置过的话) 一切都是为了访问更快. 2.如何查看自己网站的http版本 最简单的方法就F12啊,我这里是火狐 ...

  3. nginx 添加代理

    1 确认安装路径 ps aux | grep nginx 2.进入配置目录 3.使用vi编辑配置文件 如果是新增,可以参考其他配置,5yy复制相应行,p粘贴,然后修改内容后:wq保存退出 4.验证配置 ...

  4. c语言——单链表分拆——头插法创建链表,尾插法生成链表

    #if 1 #include<stdio.h> #include<stdlib.h> #include<iostream> using namespace std; ...

  5. oracle mysql 比较

    转载:https://www.cnblogs.com/qq765065332/p/9293029.html 一.数据的存储结构 mysql: 1.对数据的管理可以有很多个用户,登录用户后可以看到该用户 ...

  6. 赚钱快的app

    赚钱快的app目前强力推荐6款都是很不错的 宝石星球下载地址:http://www.baoshixingqiu.com/redPacket?key=548341 雪梨网APP下载地址 http://w ...

  7. 2018最新Python视频教程

    基础+就业Python视频教程需要的加我q:1139721002备注来意

  8. ccf-命令行选项-201403-3

    分析: 这道题不是很难 用了一个split()函数 核心是: 对命令选项的判断 不要一个字符字符的判断 要一项一项的判断 比如ab:m: 分析步骤 (1) 读取一个字符(2)判断下一步是否有字符,下一 ...

  9. log4net使用中loginfo.IsInfoEnabled=false问题解决方法

    引用了其他项目中的日志组件,调试时发现IsInfoEnabled属性一直为false 找了很多的解决办法,都不行 program.cs里面也不用添加 log4net.Config.XmlConfigu ...

  10. webshell导致项目崩溃

    mysql挂死,无法启动,解决mysql无法启动: /etc/my.cnf配置文件中innodb_force_recovery=1然后service mysqld start/etc/my.cnf配置 ...