Middleware是Django提供的一个处理request/response的hooks框架,这是一个轻且底层的插件系统,用于在全局范围改变Django的输入或输出,使用须谨慎,理论上每次请求都会执行,使用不当会影响性能。
每个中间件负责执行某些特定的功能,Django会根据规则将中间件在特定的时机被执行,例如Djaong提供的Authentication middleware,该组件将用户与对应的session相关联。
如何编写一个中间件
中间件可以作为一个函数来实现,像这样:
def
又或者可以作为一个可调用的class实现(常规是作为class实现),如下:
class
传入的get_response是一个可执行方法,如果这是最后一个中间件,则它是将要执行的视图方法,如果不是,则是下一个将被执行的中间件,当前被执行的中间件不需要知道传入的get_response到底是什么。
需要注意的是,在__init__方法中,只能接受get_response作为传入参数,不能增加其他的参数,但可以在__init__里面加全局变量。
如何让中间件生效
想要让我们编写的中间件生效,需要在Django的settings里的MIDDLEWARE下增加对应的配置。在MIDDLEWARE中,每个中间件由一串字符串表示,字符串的内容为中间件的完整python路径,举例:
MIDDLEWARE
运行时,将会按照配置的顺序,自顶向下执行。所以如果中间件依赖另一个中间件,例如, AuthenticationMiddleware将经过身份验证的用户存储在会话中;因此,它必须在之后运行SessionMiddleware 。
中间件的执行顺序
在请求阶段,Django会在调用视图之前,按照settings里MIDDLEWARE的从上至下定义的顺序调用中间件的process_request和process_view方法,先执行完所有的process_request,然后执行所有的process_view。
我们从浏览器发出一个请求 Request,得到一个响应后的内容 HttpResponse ,这个请求传递到 Django的整体的执行流程如下:
文档里将这种执行方式形容为洋葱,每个中间件都是包装视图的一层,请求到来时将按照配置层层递进的执行,在返回响应时则以反过来的顺序执行。如果请求到某一层,该层决定不调用后续的get_response,提前返回HttpResponse,执行流程将原路返回,执行在这个中间件前面的中间件的process_response和process_template_response方法,在这一层之后的中间件和视图将不会被执行。这个特性多于用户权限校验,在中间件中校验用户权限,如果用户没有权限,在这里就可以跳过后续的流程直接返回。
其他的hooks方法
除了process_request和process_response,Django还提供了三种hooks方法:
process_view(request,view_func,view_args,view_kwargs)
在Django调用视图之前会调用该函数。
它应返回一个None或一个HttpResponse 对象。如果返回None,则Django将继续处理此请求,并执行其他的process_view()中间件,然后执行相应的视图。如果它返回一个HttpResponse对象,则Django不会调用视图。它将执行中间件的process_response函数,并把HttpResponse作为返回结果。
process_exception(request, exception)
当视图发出异常时,Django会调用这个函数。 process_exception()应该返回一个None或一个 HttpResponse对象。如果它返回一个 HttpResponse对象,则将直接调用template response和response函数,并将结果响应返回到浏览器。否则,将启动默认异常处理。
process_template_response(request, response)
如果视图调用了render()方法,Django会在视图调用结束后理解调用这个方法。
它必须返回实现render()方法的response object,并且可以修改传入的response或者创建一个新的TemplateResponse。
使用场景举例
选两个简单的例子,做抛砖引玉。
打印日志
在执行视图前后,对request、response的相关数据进行打印,无需在领域层代码中进行进行打印动作。
用户校验
可参考django给出的这个例子AuthenticationMiddleware
参考:
https://docs.djangoproject.com/en/3.0/topics/http/middleware/
Django documentationdocs.djangoproject.com