[TimLinux] Django 中间件

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)之后执行。
原文地址:https://www.cnblogs.com/timlinux/p/9253497.html