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函数返回的过程中,其执行顺序是,按照配置的中间键顺序从下往上执行的。

image

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. 参考文章

1. Django源码解析(四) 中间件

2. https://docs.djangoproject.com/en/1.8/topics/http/middleware/#process_view

 

posted @ 2015-11-02 12:10  weishenhong  阅读(1306)  评论(0编辑  收藏  举报