1. 定义
中间件是一个钩子框架,深入到django的请求/响应处理过程中。这是一个轻量、底层插件系统,目的是全局修改django的输入或输出。每一个中间件组件都是用来处理特定的功能。例如django中间件组件:AuthenticationMiddleware用来关联请求用户,采用的方式是使用session。
2. 原理
中间件工厂是一个可调用对象,接收get_response作为参数,并返回一个中间件,返回的中间件也是一个可调用对象,接收一个request,并返回一个response,向一个view函数,中间件工厂其实很像装饰器。具体实现方式有:函数方式(像使用函数实现的装饰器)、类方式(像使用类实现的装饰器)。示例代码如下:
def simple_middleware(get_response): # 这里添加代码:一次性配置和初始化 def middleware(request): # 这里添加代码:在view、下一个中间件执行之前执行的代码 response = get_response(request) # 这里添加代码:view调用之后,为每一个请求/响应代码 return response return middleware class SimpleMiddleware(object): def __init__(self, get_response): self.get_response = get_response # 这里添加代码:一次性配置和初始化 def __call__(self, request): # 这里添加代码:在view、下一个中间件执行之前执行的代码 response = get_response(request) # 这里添加代码:view调用之后,为每一个请求/响应代码 return response
get_response可调用对象是由django提供的:可能是一个真实的view函数(如果是最后列出的中间件)、或者中间件链中的下一个中间件。当前中间件不需要知道或者关心get_response是什么,只要明白它将呈现下一步内容。
3. 存放路径
中间件是存放在一个Python文件中,可能放在任意Python搜索文件方式的路径中,只要能够在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.middleware.clickjacking.XFrameOptionsMiddleware', ]
4. 解析步骤
根据请求阶段,在调用view函数之前,django按照定义在MIDDLEWARE中的顺序,从上往下应用中间件。请求是从上往下一层一层往下传递get_response,直到核心(view),响应则是返回来的顺序(由核心开始)。如果某一层决定短路并返回一个响应,而没有调用它的get_repsonse,那么在内部的层(包括view函数)都将被看不到请求和响应。
顺序:__call__: 前部分 --> self.get_response(request) --> 后部分
self.get_response(request)内部顺序:process_view() -> view函数
多个中间件:同名函数先执行,比如:(中间件A的__call__前部分 --> 中间件B的前部分)前部分 --> (中间件A的process_view --> 中间件B的process_view)self.get_response(request) --> (中间件B的__call__后部分 --> 中间件A的后部分)后部分
5. 中间件钩子
出了前面描述的基本请求响应中间件模式,你可以添加另外三个特殊的方法(基于类的中间件),另外还有两个函数是旧式风格(MIDDLEWARE_CLASSES):
5.1. process_view():
process_view(request, view_func, view_args, view_kwargs)
- request:请求对象,view_func:函数对象,view_args: view的位置参数,view_kwargs: view的关键字参数,view_args和view_kwargs都不包含request对象(第一个view参数)
- 在django调用view之前调用该函数
- 返回None(将继续处理请求,执行其他中间件提供的process_view函数,并且核心的view函数)、或者HttpResponse对象(将不再调用下面的流程,将返回结果到前端)
5.2. process_exception():
process_exception(request, exception)
- request:请求对象,exception: view函数抛出的一次对象
- 当一个view抛出了异常后,将调用该函数
- 返回None(默认异常处理流程)、或者HttpResponse对象(模板响应、中间件响应将被应用上、并且响应结果返回给浏览器)
5.3. process_template_response():
process_template_response(request, response)
- request: 请求对象,response: 由view或者中间件返回的TemplateResponse对象
- 在view完成执行之后调用该函数。
- 必须返回一个实现了render方法的响应对象。通过response.template_name, response.context_data来修改传递的响应对象,也可以参加并绑定新的TemplateResponse对象。
- 不需要明确指定render响应,影响将在所有模板响应中间件完成调用之后自动render。
5.4. process_request():
process_request(request)
- request: 请求对象
- 这个相当于__call__()中调用self.get_response(request)之前的代码部分
- process_request和process_response要生效必须在__call__中明确指定调用,也可以通过继承:MiddlewareMixin类来隐式调用这两个方法。
class MiddlewareMixin(object): def __init__(self, get_response): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response
5.5. process_response():
process_response(request, response)
- request: 请求对象,response: 响应对象
- 这个相当于把self.get_response(request)返回的response对象,和reques对象传递给该函数,该函数在self.get_response(request)之后执行。