Django源码解析:middleware
1. middleware简介
Django的middleware的概念相当于SSH框架里面的filter的概念。中间键的作用就是对所有的request,在request前,和在response后做一定的处理。
Django的中间键类型分为五种:
- 请求(Request)中间件->对应函数process_request
- 视图(View)中间件->对应函数process_view
- 模板(Template)中间件->对应函数process_template_response
- 响应(Response)中间件->对应函数process_response
- 异常(Exception)中间件->对应函数process_exception
我们在自定义中间键的时候,至少需要实现上面的五个函数之一。
2. middleware中间键函数的执行顺序和过程
(1)总述
1. 应用请求中间件,处理传入请求.如果请求中间件方法process_request返回的response非空,则终止处理过程,执行步骤7.
2. url匹配,查找视图函数
3. 应用视图中间件,处理传入请求 视图与视图参数.如果视图中间件方法process_view返回的response非空,则终止处理过程,执行步骤7.
4. 调用视图函数.
5. 如果视图函数抛出异常 ,应用异常中间件,处理传入请求与异常.如果异常中间件方法process_exception回的response非空,则终止处理过程.无论是否终止过程,都会跳到步骤7.
6. 如果response支持延迟渲染,应用模板中间件.(If the response supports deferred rendering, apply template response middleware and the render the response).执行步骤7.
7. 应用响应中间件,处理传入请求与中间件返回的response.
(2)当Handler接受到客户端的请求过程的处理细节过程
具体的处理函数的文件定义在django/core/handler/base.py文件之中
当handler接受到一个客户端的请求的时候,其执行过程如下
1. 根据setting.py配置的MIDDLEWARE_CLASSES,import相应的包。然后很据里面定义的5中类型的中间键,提取出来,保存在self._request_middleware,self._view_middleware ,self._template_response_middleware ,self._response_middleware ,self._exception_middleware这五个list变量中。
self._view_middleware = [] self._template_response_middleware = [] self._response_middleware = [] self._exception_middleware = [] request_middleware = [] for middleware_path in settings.MIDDLEWARE_CLASSES: mw_class = import_string(middleware_path) try: # 实例化该middleware 如果不存在该类文件,则跳过 mw_instance = mw_class() except MiddlewareNotUsed: continue if hasattr(mw_instance, 'process_request'): request_middleware.append(mw_instance.process_request) if hasattr(mw_instance, 'process_view'): self._view_middleware.append(mw_instance.process_view) # 倒序的插入的,因此从reponse后的middleware的函数,是从后往前执行的 if hasattr(mw_instance, 'process_template_response'): self._template_response_middleware.insert(0, mw_instance.process_template_response) if hasattr(mw_instance, 'process_response'): self._response_middleware.insert(0, mw_instance.process_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.insert(0, mw_instance.process_exception)
从上面的代码我们也可以看出:对于配置的middleware中间键,其执行过程是有顺序的。在request传入的过程中,process_request和process_view函数,是按照配置的顺序从上往下执行的。在response函数返回的过程中,其执行顺序是,按照配置的中间键顺序从下往上执行的。
2.执行request的middleware
从代码中,我们可以看出,当middleware函数返回非None的时候,就直接跳转到response的middleware的阶段了,不再去继续执行下面的request的middleware函数。
# Apply request middleware # 遍历前面保存的middleware里面的request方法,并且进行执行 for middleware_method in self._request_middleware: # request方法是没有返回值的,如果有返回那么就退出了 response = middleware_method(request) if response: break
3.根据请求的路径,查找相应的处理的view
if response is None: # 根据reques.path_info和配置的urlconf的urls进行匹配,查找相应的处理的view if hasattr(request, 'urlconf'): # Reset url resolver with a custom urlconf. # 该request可能有自己的urlconf urlconf = request.urlconf urlresolvers.set_urlconf(urlconf) resolver = urlresolvers.RegexURLResolver(r'^/', urlconf) resolver_match = resolver.resolve(request.path_info) callback, callback_args, callback_kwargs = resolver_match request.resolver_match = resolver_match
4. 执行view的middleware
# Apply view middleware # 执行view的middlerware for middleware_method in self._view_middleware: response = middleware_method(request, callback, callback_args, callback_kwargs) if response: break
5.执行view函数,得到response。如果有异常,就执行exception的middleware
if response is None: # 执行view函数 wrapped_callback = self.make_view_atomic(callback) try: response = wrapped_callback(request, *callback_args, **callback_kwargs) # 如果出现异常,那么就执行异常的middleware except Exception as e: # If the view raised an exception, run it through exception # middleware, and if the exception middleware returns a # response, use that. Otherwise, reraise the exception. for middleware_method in self._exception_middleware: response = middleware_method(request, e) if response: break if response is None: raise
6. 执行response的middleware,得到最终的返回给客户端的response
# If the response supports deferred rendering, apply template # response middleware and then render the response # 如果是render类型的response,就去执行render的middleware if hasattr(response, 'render') and callable(response.render): for middleware_method in self._template_response_middleware: response = middleware_method(request, response) response = response.render()
3. 参考文章
2. https://docs.djangoproject.com/en/1.8/topics/http/middleware/#process_view