Django中间件

每个中间件组件负责完成某个特定的功能。

一、中间件概念

Django中间件是修改Django reuqest 或者 response对象的钩子,可理解为是介于HttpRequest与HttpResponse处理之间的一道处理过程。浏览器从请求到响应的过程中,Djnago需要通过很多中间件处理,如下图:

Django中间件_第1张图片

你可以想象成一个洋葱:每个中间件类都是一个“层”,它覆盖了洋葱核心的视图。 如果请求通过洋葱的所有层(每个调用get_response将请求传递到下一层),一直到核心的视图,响应将通过在每一层(以相反的顺序)的路上退出。

如果其中一个层决定短路并返回响应而不调用其get_response,那么该层(包括视图)内的洋葱层都不会看到请求或响应。 响应将只返回通过请求传递的相同的层 。 

Django中间件_第2张图片

 中间件函数执行流程:

  1. 请求到达中间件后先依次执行每个中间件的process_request函数;
  2. 再依次执行每个中间件的process_view函数,找到我们的视图函数;
  3. 执行视图函数处理请求数据
  4. 若在上面的过程中出现异常,则依次反方向执行每个中间件的process_exception函数;
  5. 如果请求包含模板渲染,则依次反方向执行每个中间件的process_template_response函数;
  6. 最后一次反方向执行每个中间件的process_response函数。
以上这些执行函数将返回None或者HttpResponse函数。若返回None,则交给下一个中间件的对应函数处理;若返回HttpResponse对象,则将其返回给用户
请求到达中间件之后,先按照正序执行每个注册中间件的process_request方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法( 注意不是掉头执行所有的process_response方法),将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。

Django中间件_第3张图片

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

Django中间件_第4张图片

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

Django中间件_第5张图片

Django中间件作用

  • 修改请求,即传送到view中的HttpRequest对象;
  • 修改响应,即view返回的HttpResponse对象。
登陆认证:在中间件中加入登陆认证,所有请求就自动拥有登陆认证,如果需要放开部分路由,只需要特殊处理就可以了。
流量统计:可以针对一些渲染页面统计访问流量。
恶意请求拦截:统计IP请求次数,可以进行频次限制或者封禁IP。

Django中间件位置

中间件组件配置在settings.py文件的MIDDLEWARE选项列表中,配置中的每个字符串选项都是 一个类,也就是一个 中间
Django 默认的中间件配置: 中间件的顺序很重要
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware', # 主要是针对安全访问处理,把http请求重定向到https请求
    'django.contrib.sessions.middleware.SessionMiddleware',  # 开启会话支持
    'django.middleware.common.CommonMiddleware',   # 检测是否允许浏览器类型、检查是否需要添加/
    'django.middleware.csrf.CsrfViewMiddleware',   # 添加跨站点请求伪造csrf的保护,通过向POST表单添加一个隐藏的表单字段,并检查请求中是否有正确的值
    'django.contrib.auth.middleware.AuthenticationMiddleware', # 向每个接收到的user对象添加HttpRequest属性,表示当前登录的用户
    'django.contrib.messages.middleware.MessageMiddleware',    # 开启基于Cookie和会话的消息支持
    'django.middleware.clickjacking.XFrameOptionsMiddleware',  # 对点击劫持的保护
]

二、自定义中间件

中间件可以定义五个方法,分别是:
process_request(self, request)
process_view(self, request, view_func, view_args, view_kwargs)
process_exception(self, request, exception)
process_template_response(self, request, response)
process_response(self, request, response)
以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

2.1、自定义中间的步骤

1、在 app 目录下新建一个 py 文件,名字自定义,并在该 py 文件中导入 MiddlewareMixin:
from django.utils.deprecation import MiddlewareMixin
Django中间件_第6张图片
2、自定义的中间件类,要继承父类 MiddlewareMixin:
class MD1(MiddlewareMixin):
    pass

3、在 settings.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',
   
    'app01.middlewares.MD1',  # 自定义中间件
]

2.2、自定义中间件类的方法

自定义中间件类的方法有:process_request 和 process_response。

Django中间件_第7张图片

2.2.1、process_request 方法--Request预处理函数

process_request(self, request) 方法有一个参数 request,这个 request 和视图函数中的 request 是一样的。
返回值:
 process_request 方法的返回值可以是 None 也可以是 HttpResponse 对象:  
    * 返回值是 None 的话,按正常流程继续走,交给下一个中间件处理或路由系统处理
    * 返回值是 HttpResponse 对象,Django将不再执行任何除了本层process_response以外其它的中间件以及相应的view,Django将立即返回该HttpResponse给浏览器。
process_request 方法是在视图函数之前执行的,更确切地说是未解析url、未确定要运行的视图函数前。
当配置多个中间件时,会按照 MIDDLEWARE中 的注册顺序,也就是列表的索引值,顺序执行。
不同中间件之间传递的 request 参数都是同一个请求对象。
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse

class MD1(MiddlewareMixin):
    def process_request(self, request):
       print("md1  process_request 方法。", id(request)) # 在视图之前执行

2.2.2、process_response 方法

process_response 方法有两个参数,一个是 request,一个是 response, request 是请求对象,response 是视图函数返回的 HttpResponse 对象。
返回值:
该方法必须要有返回值,且必须是HttpResponse对象。如果不返回response而返回其他对象,则浏览器不会拿到Django后台给他的视图,而是中间件中返回的对象。
process_response 方法是在视图函数之后执行的。
当配置多个中间件时,会按照 MIDDLEWARE 中的注册顺序,也就是列表的索引值,倒序执行。
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("md1  process_request 方法。", id(request)) #在视图之前执行


    def process_response(self,request, response): :#基于请求响应
        print("md1  process_response 方法!", id(request)) #在视图之后
        return response
从下图看,正常的情况下按照绿色的路线进行执行,假设 中间件1 有返回值,则按照红色的路线走,直接执行该类下的 process_response 方法返回,后面的其他中间件就不会执行

Django中间件_第8张图片

2.2.3、process_view 方法--View与处理函数

process_view 方法格式如下:
process_view(self, request, view_func, view_args, view_kwargs)

process_view 方法有四个参数:

 request 是 HttpRequest 对象。
 view_func 是 Django 即将使用的视图函数。(它是实际的函数对象,而不是函数的名称作为字符串。)
 view_args 是将传递给视图的位置参数的列表。
 view_kwargs 是将传递给视图的关键字参数的字典。
view_args 和 view_kwargs 都不包含第一个视图参数(request)
process_view 方法是在 Django路由系统之后、 调用视图函数之前执行的。
返回值:
 返回值可以是 None、view_func(request) 或 HttpResponse 对象。
    1、返回值是 None 的话,Django将继续处理这个request ,执行后续的中间件, 然后调用相应的view。
    2、返回值是 HttpResponse 对象,将不会执行Django的视图函数,而是直接在中间件中掉头,倒序执行一个个process_response方法,最后返回给浏览器
    3、返回值是 view_func(request),Django 将不执行后续视图函数之前执行的方法,提前执行视图函数,然后再倒序执行视图函数之后执行的方法。
    4、当最后一个中间件的 process_request 到达路由关系映射之后,返回到第一个中间件 process_view,然后依次往下,到达视图函数
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("md1  process_request 方法。", id(request)) #在视图之前执行

    def process_response(self,request, response): :#基于请求响应
        print("md1  process_response 方法!", id(request)) #在视图之后
        return response

    def process_view(self,request, view_func, view_args, view_kwargs):
        print("md1  process_view 方法!") #在视图之前执行 顺序执行
        #return view_func(request)

从下图看,正常的情况下按照绿色的路线进行执行,假设中间件1有返回值,则按照红色的路线走,直接执行该类下的 process_response 方法

Django中间件_第9张图片

 1.2.4、process_exception 方法--Exception后处理函数

process_ exception 方法格式如下:
process_exception(self, request, exception)

参数:

 request 是 HttpRequest 对象。
 exception 是视图函数异常产生的 Exception 对象。
process_exception 方法 只有在视图函数中出现异常了才执行, 按照 settings 的注册倒序执行。
在视图函数之后,在 process_response 方法之前执行。
返回值:
process_exception 方法的返回值可以是一个 None 也可以是一个 HttpResponse 对象。
    1、返回值是 None,页面会报 500 状态码错误,视图函数不会执行。process_exception 方法倒序执行,然后再倒序执行 process_response 方法。
    2、返回值是 HttpResponse 对象,页面不会报错,返回状态码为 200。视图函数不执行,该中间件后续的 process_exception 方法也不执行,直接从最后一个中间件的process_response 方法倒序开始执行。
    若是 process_view 方法返回视图函数,提前执行了视图函数,且视图函数报错,则无论 process_exception 方法的返回值是什么,页面都会报错, 且视图函数和 process_exception 方法都不执行。
    直接从最后一个中间件的 process_response 方法开始倒序执行:
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("md1  process_request 方法。", id(request)) #在视图之前执行

    def process_response(self,request, response): #基于请求响应
        print("md1  process_response 方法!", id(request)) #在视图之后
        return response

    def process_view(self,request, view_func, view_args, view_kwargs):
        print("md1  process_view 方法!") #在视图之前执行 顺序执行
        #return view_func(request)


    def process_exception(self, request, exception):#引发错误 才会触发这个方法
        print("md1  process_exception 方法!")
        # return HttpResponse(exception) #返回错误信息

1.2.5、process_template_response 方法

方法格式如下:
process_template_response(self, request, response)
参数:
 request 是 HttpRequest 对象。
 response 是TemplateResponse对象(由视图函数或者中间件产生)
process_template_response 方法是在视图函数完成后立即执行的, 但是有个前提:视图函数返回的对象有一个render()方法(或者表明该对象是TemplateResponse对象)。
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("md1  process_request 方法。", id(request)) #在视图之前执行


    def process_response(self,request, response): :       #基于请求响应
        print("md1  process_response 方法!", id(request)) #在视图之后
        return response

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

view.py:
def index(request):
    print("app_1 中的 index视图")

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

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

参考

        https://blog.csdn.net/hua1011161696/article/details/80820228  Django学习(三):中间件
        https://www.cnblogs.com/featherwit/p/13497065.html  django基础之Django中间件
        https://cloud.tencent.com/developer/article/1631561   Django中间件看完这篇彻底明白      侧重讲解各个中间件实现原理

你可能感兴趣的:(web框架,中间件,django)