中间件介绍 :
官方的说法:
中间件是一个用来处理Django的请求和响应的架构级别的钩子, 他是一个轻量, 低级别的插件系统, 用于在全局范围改变Django的输入和输出. 每个中间件组件都负责做一些特定的功能.
但是由于其影响的是全局, 所以需要谨慎使用, 使用不当会影响性能.
直白的说法:
中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作, 它本质上就是一个自定义类, 类中定义了几个方法, Django框架会在处理请求的特定的时间去执行这些方法.
配置:
我们一直都在使用中间件, 只是没有注意而已, 打开Django项目的Settins.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', ]
MIDDLEWARE配置项是一个列表, 列表中是一个个字符串, 这些字符串其实是一个个类, 也就是一个个中间件.
自定义中间件 :
中间件可以定义五个方法, 分别是:
process_request(self, request)
process_response(self, request, response)
process_view(self, request, view_func, view_args, view_kwargs)
process_exception(self, request, exception)
process_template_response(self,request,response)
以上方法的返回值可以是None或一个HttpResponse对象, 如果是None, 则继续按照django定义的规则向后继续执行, 如果是HttpResponse对象, 则直接将该对象返回给用户.
举个栗子:
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
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', 'middlewares.MD1', # 自定义中间件MD1 'middlewares.MD2' # 自定义中间件MD2 ]
process_request:
process_request有一个参数, 就是request, 这个request和视图函数中的request是一样的.
process_request的返回值可以是None, 也可以是HttpResponse对象. 返回值是None的话, 按正常流程继续执行, 交给下一个中间件处理, 如果是HttpResponse对象, Django将不执行视图函数, 而将响应对象返回给浏览器.
1. 执行时间:
在视图函数执行之前, 路由匹配之前
2. 参数:
request 视图函数用到的request
3. 执行顺序:
按照settings中注册顺序顺序执行. 也就是列表的索引值, 从前到后一次执行.
4. 返回值:
None 正常流程执行
HttpResponse对象 当前中间件后面(注册中的下面)的中间件的process_request和process_response方法, 视图函数都不执行. 执行当前中间件的process_response方法以及之前(注册中的上面)的中间件的process_response方法.
process_response :
process_response 有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。
1. 执行时间:
在视图函数执行之后
2. 参数:
request 视图函数中用到的request
response 视图函数中返回的response
3. 返回值:
必须是response对象
4. 执行顺序:
按照注册顺序倒叙执行
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并返回结果。
1. 执行时间:
在process_request执行之后, 以及路由匹配之后, 在视图函数执行之前.
2. 参数:
request是HttpRequest对象
view_func 要执行的额视图函数
view_args 视图函数的位置参数
view_kwargs 视图函数的关键字参数
3. 返回值:
None 正常按流程执行
HttpResponse对象 按照注册顺序顺序执行, 当其中一个中间件的process_view方法返回HttpResponse对象时, 此process_view方法下面的process_view方法和视图函数不再执行, 转去执行所有中间件的process_response方法. 并将process_view方法返回的HttpResponse对象返回给浏览器.
4. 执行顺序:
按照注册顺序的顺序执行(从上往下执行)
process_exception :
process_exception(self, request, exception), 该方法有两个参数:
一个HttpResponse对象
一个exception是视图函数异常产生的Exception对象
此方法只有在视图函数中出现异常了才执行, 它返回的值可以是一个None, 也可以是一个HttpResponse对象. 如果是HttpResonse对象, django将调用模板和中间件中的process_response方法, 并返回给浏览器, 否则将默认处理异常. 如果返回一个None, 则交给下一个中间件的process_exception方法来处理异常.
1. 执行时间:
在视图函数之后, 在process_response之前
2. 参数:
exception 错误信息对象
3. 返回值:
None 正常流程执行
HttpResponse对象 如果某一个中间件的process_exception方法返回一个HttpResponse对象, 那么所有此process_exception方法之前的process_exception方法都不执行, 转去执行所有中间件的process_response方法.
4. 执行顺序:
按照注册顺序的倒叙执行
process_template_response :
process_template_response(self, request, response), 该方法有两个参数, 一个是HttpResponse对象, 而response是TemplateResponse对象(由视图函数或者中间件产生).
process_template_response实在视图函数执行完成后立即执行, 但是有一个前提条件, 那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法).
1. 执行时间(触发条件: response对象要有一个render方法)
在视图函数之后, 在process_response方法之前
2. 参数:
request 一个HttpRequest对象
response TemplateResponse对象(由视图函数或者中间件产生)
3. 返回值:
返回response对象, 不能返回None
4. 执行顺序:
按照注册顺序的倒叙执行
中间件的执行流程 :
当请求到达中间件之后, 先按照正常顺序执行每个注册中间件的process_request方法返回的值是None, 就依次执行. 如果返回的值是HttpResponse对象, 不再执行后面的process_request方法, 而是执行当前对应中间件的process_response, 将HttpResponse对象返回给浏览器.
也就是说: 如果MIDDLEWARE中注册了6个中间件, 在执行过程中, 第3个中间件返回了一个HttpResponse对象, 那么第4,5,6位置的中间件的process_request和process_response方法都不执行, 顺序执行3,2,1位置的中间件process_response方法.
process_request方法都执行完毕后, 找到要执行的视图函数, 先不执行视图函数, 限制性中间件中的process_view方法, process_view方法返回None, 继续按顺序执行, 所有process_view方法执行完毕后执行视图函数.
假如中间件3中的process_view方法返回了HttpResponse对象, 则4,5,6中间件的process_view以及所有的视图函数都不执行, 直接从最后一个中间件, 也就是6中间件的process_response方法开始倒序执行.
process_exception和process_template_response两个方法都是有触发条件的, 执行顺序也是倒叙.
总结所有的执行流程如下:
Django请求流程图 :