中间件

方式一:函数式:中间件[middleware],也叫钩子方法[钩子函数],hook

Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。

我们可以使用中间件,在Django处理视图的不同阶段对输入或输出进行干预。

 中间件的定义方法

中间件工厂函数需要接收一个可以调用的get_response对象。

返回的中间件也是一个可以被调用的对象,并且像视图一样需要接收一个request对象参数,返回一个response对象。

def simple_middleware1(get_response):
# 项目启动时执行的代码。
print("simple_middleware1---__init__项目初始化") # 这个子函数会在用户请求的时候才会执行
def middleware(request):
# 此处编写的代码会在每个请求处理视图前被调用。
print("simple_middleware1---视图执行请求之前的代码,解密,验证权限")
response = get_response(request) # 此处编写的代码会在每个请求处理视图之后被调用。
print("simple_middleware1---视图执行响应之后的代码,加密,操作记录")
return response return middleware def simple_middleware2(get_response):
# 项目启动时执行的代码。
print("simple_middleware2---__init__项目初始化") # 这个子函数会在用户请求的时候才会执行
def middleware(request):
# 此处编写的代码会在每个请求处理视图前被调用。
print("simple_middleware2---视图执行请求之前的代码,解密,验证权限")
response = get_response(request) # 此处编写的代码会在每个请求处理视图之后被调用。
print("simple_middleware2---视图执行响应之后的代码,加密,操作记录")
return response return 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.simple_middleware1',
'app01.middlewares.simple_middleware2',
]

注册添加两个中间件

方式二:类对象

1、中间件的概念

  中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

  Django的中间件的定义:

1
Middleware is a framework of hooks into Django’s request/response processing. <br>It’s a light, low-level “plugin” system for globally altering Django’s input or output.

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

  可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。

  Django默认的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配置项是一个列表,列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。

  我们之前已经接触过一个csrf相关的中间件了?我们一开始让大家把他注释掉,再提交post请求的时候,就不会被forbidden了,后来学会使用csrf_token之后就不再注释这个中间件了。

  那接下来就为大家解开神秘的面纱,深入探索一下。学习中间件中的方法以及这些方法什么时候被执行。

2、自定制中间件

  中间件可以定义五个方法,分别是:

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

3、自定制中间件示例

 
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

4、process_request方法

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

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

  我们来看看多个中间件时,Django是如何执行其中的process_request方法的。

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")

  在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.MyMiddleware.MD1', # 自定义中间件MD1
'app01.MyMiddleware.MD2' # 自定义中间件MD2
]

  此时,我们访问一个视图,会发现终端中打印如下内容:

1
2
3
MD1里面的 process_request
MD2里面的 process_request
app01 中的 index视图

  把MD1和MD2的位置调换一下,再访问一个视图,会发现终端中打印的内容如下:

1
2
3
MD2里面的 process_request
MD1里面的 process_request
app01 中的 index视图

  看结果我们知道:视图函数还是最后执行的,MD2比MD1先执行自己的process_request方法。

  在打印一下两个自定义中间件中process_request方法中的request参数,会发现它们是同一个对象。

  由此总结一下:

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

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

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

5、process_response方法

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

  给上述的M1和M2加上process_response方法:

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

  访问一个视图,看一下终端的输出:

1
2
3
4
5
MD1里面的 process_request
MD2里面的 process_request
app01 中的 index视图
MD2里面的 process_response
MD1里面的 process_response

  看结果可知:

    process_response方法是在视图函数之后执行的,(此时settings.py中 MD1比MD2先注册)所以顺序是MD2比MD1先执行。

    多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse class MD1(MiddlewareMixin): def process_request(self, request):
print("我是MD1 process_request方法")
return HttpResponse("xxxxxxxx") 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 #打印结果:
#我是MD1 process_request方法
#我是MD1 process_response process_request方法里面有返回值,将不走下面的中间件和视图函数了 直接走到process_response class MD1(MiddlewareMixin): def process_request(self, request):
print("我是MD1 process_request方法")
return HttpResponse("xxxxxxxx") def process_response(self, request, response):
print("我是MD1 process_response")
return response class MD2(MiddlewareMixin): def process_request(self, request):
print("我是MD2 process_request方法")
return HttpResponse("xxxxxxxx") def process_response(self, request, response):
print("我是MD2 process_response")
return response
#打印结果:
#我是MD1 process_request方法
#我是MD2 process_request方法
#我是MD2 process_response
#我是MD1 process_response

特殊返回

6、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并返回结果。

  给MD1和MD2添加process_view方法:

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__) 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__)

  访问index视图函数,看一下输出结果:

1
2
3
4
5
6
7
8
9
10
11
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

  process_view方法是在process_request之后,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse 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("我是MD1 process_view方法")
return HttpResponse("md1...xxxxxxxx") 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("我是MD2 process_view方法") #打印结果:
我是MD1 process_request方法
我是MD2 process_request方法
我是MD1 process_view方法
我是MD2 process_response
我是MD1 process_response 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("我是MD1 process_view方法") 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("我是MD2 process_view方法")
return HttpResponse("md2...xxxxxxxx")
#打印结果:
我是MD1 process_request方法
我是MD2 process_request方法
我是MD1 process_view方法
我是MD2 process_view方法
我是MD2 process_response
我是MD1 process_response

特殊返回

7、process_exception

  process_exception(self, request, exception)

  该方法两个参数:

    • HttpRequest对象
    • exception是视图函数异常产生的Exception对象。

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

  给MD1和MD2添加上这个方法:

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") 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")

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

  想办法,在视图函数中抛出一个异常:

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

  在MD2的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

  注意,这里并没有执行MD1的process_exception方法,因为MD2中的process_exception方法直接返回了一个响应对象。

8、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视图,终端输出的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MD1里面的 process_request
MD2里面的 process_request
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x000000000B46DBF8> index
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x000000000B46DBF8> index
app01 中的 index视图
MD2 中的process_template_response
MD1 中的process_template_response
in index/render
MD2里面的 process_response
MD1里面的 process_response

  从结果看出:

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

9、源码试读

  作为延伸扩展内容,有余力的同学可以尝试着读一下以下两个自带的中间件:

1
2
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',

07 Django组件-中间件的更多相关文章

  1. Django组件-中间件

    1.中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影 ...

  2. 15 Django组件-中间件

    中间件 中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好 ...

  3. Django 组件-中间件

    中间件 中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好 ...

  4. Django组件——分页器和中间件

    分页器 Django内置分页器(paginator) 分页器函数为paginator,里面有几个重要的参数需要我们了解 paginator = Paginator(book_list, 10) #第二 ...

  5. Django组件---Django请求生命周期和中间件

    Django组件---Django请求生命周期和中间件 Django请求生命周期 说明: client代表浏览器,浏览器的内部为我们封装了socket,Django的WSGI模块也为我们封装了sock ...

  6. Django组件 之中间件

    -------------------------------------------------------------------落花不是无情物,待到山花烂漫时. 中间件 中间件的概念 中间件顾名 ...

  7. django组件:中间件

    全局性的逻辑处理 一.中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨 ...

  8. Django组件 - Django请求生命周期、中间件

    一.Django请求生命周期 在学习中间件之前,先了解一下Django的请求生命周期,如下图: 1)client代表浏览器,浏览器内部为我们封装了socket,Django的WSGI模块也封装了soc ...

  9. python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)

    一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...

随机推荐

  1. Java反射获取class对象的三种方式,反射创建对象的两种方式

    Java反射获取class对象的三种方式,反射创建对象的两种方式 1.获取Class对象 在 Java API 中,提供了获取 Class 类对象的三种方法: 第一种,使用 Class.forName ...

  2. oracle启动停止命令

    dba 连接 oracle(切到 oracle 用户) sqlplus /nolog conn / as sysdba 登录成功之后,关闭数据库服务 shutdown immediate 登录成功之后 ...

  3. [bzoj1614][Usaco2007Jan]Telephone Lines 架设电话线_二分答案_最短路

    Telephone Lines bzoj-1614 Usaco-2007Jan 题目大意:给你一个n个点m条边的带边权无向图,求最短路.可以选取k条边免费. 注释:$1\le n\le 10^3$,$ ...

  4. codevs——T1267 老鼠的旅行

    http://codevs.cn/problem/1267/  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Descr ...

  5. UVA The Tower of Babylon

    The Tower of Babylon Perhaps you have heard of the legend of the Tower of Babylon. Nowadays many det ...

  6. POJ 2029

    二维树状数组可解此题 #include <iostream> #include <cstdio> #include <cstring> #include <a ...

  7. PHP扩展开发-测验成功

    原文:http://kimi.it/496.html http://blog.csdn.net/u011957758/article/details/72234075 ---------------- ...

  8. codechef Little Elephant and Bombs题解

    The Little Elephant from the Zoo of Lviv currently is on the military mission. There are N enemy bui ...

  9. SQL Server中如何设置对列的权限

    一.方式一:使用视图 将需要限制用户只能看到特定的几个列.设置成一个视图,然后对这个视图进行权限控制 二.方式二:使用GRANT语句 1.授予相关列的查询权限(SELECT) 在数据库db1中,登录名 ...

  10. HDU 2586 How far away ?(LCA模板 近期公共祖先啊)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the vi ...