社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Django

[精华] Django学习之 一次请求到响应全过程分析

支付小哥 • 8 年前 • 3231 次点击  

Django的请求到响应的处理流程本质上差不多,简单来说,都是利用WSGI,针对request,进行response。当然在响应前会发送request_started信号,会调用预处理函数(在Flask中是before_request,Django是请求中间件,process_request),响应完成后会发送request_finished函数,调用响应后函数(在Flask中是after_request中,Django中是process_response)。思想差不多,但是处理细节上还是有很多不同的。

  1. 用户浏览器一个url,发起一个请求

在Web应用启动后,会生成一个 WSGIHandler 实例(根据setting中的WSGI_APPLICATION = ‘dailyblog.wsgi.application’ 调用函数),每次请求响应都用这个实例。 settings 里设置了 WSGI application。 返回实例代码:

from django.core.handlers.wsgi import WSGIHandler
def get_wsgi_application():
        """
        The public interface to Django's WSGI support. Should return a WSGI
        callable.

        Allows us to avoid making django.core.handlers.WSGIHandler public API, in
        case the internal WSGI implementation changes or moves in the future.
        """
        django.setup()
        return WSGIHandler()

WSGIHandler继承自BaseHander。这个处理器会导入项目中的 settings模块、导入 自定义例外类,最后调用自己的 load_middleware 方法,加载所有列在 MIDDLEWARE_CLASSES 中的 middleware 类并且内省它们。

BaseHander部分源代码:

class BaseHandler(object):
        # Changes that are always applied to a response (in this order).
        response_fixes = [
                http.conditional_content_removal,
        ]

        def __init__(self):
                self._request_middleware = None
                self._view_middleware = None
                self._template_response_middleware = None
                self._response_middleware = None
                self._exception_middleware = None

请注意,只有第一次请求时会调用 load_middleware,以后不再调用了。 其中,request_middleware、view_middleware 是顺序,template_response_middleware、response_middleware、exception_middleware 是逆序。

一 个 middleware 类可以包括请求响应过程的四个阶段:request,view,response 和 exception。对应的方法:process_request,process_view, process_response 和 process_exception。我们在middleware中间件中定义其中的方法。

3、构造WSGIRequest。 WSGIHandler 处理器准备工作已经完成,随后它给调度程序发送一个信号 request_started(这个和Flask中的request_started信号差不多),然后根据入 environ 构造 WSGIRequest 对象,它的父类是HttpRequest。

4、 处理Middleware的request中间件 WSGIHander的get_response方法处理 _request_middleware 实例变量并调用其中的每一个方法,传入 HttpRequest 的实例作为参数,即请求到达Request Middlewares,中间件对request做一些预处理,如果中间件返回response,会直接响应请求。

5、 URLConf通过urls.py文件和请求的URL找到相应的视图函数

此时会创建django.core.urlresolvers.RegexURLResolver 的一个实例。

URLresolver 遵循一个相当简单的模式。对于在 URL 配置文件中根据 ROOT_URLCONF 的配置产生的每一个在 urlpatterns 列表中的条目,它会检查请 求的URL 路径是否与这个条目的正则表达式相匹配,如果是的话,有两种选择:

如果这个条目有一个可以调用的 include,resolver 截取匹配的 URL,转 到 include 指定的 URL 配置文件并开始遍历其中 urlpatterns 列表中的 每一个条目。根据你 URL 的深度和模块性,这可能重复好几次。 否则,resolver 返回三个条目:匹配的条目指定的 view function;一个 从 URL 得到的未命名匹配组(被用来作为 view 的位置参数);一个关键 字参数字典,它由从 URL 得到的任意命名匹配组和从 URLConf 中得到的任 意其它关键字参数组合而成。

注意这一过程会在匹配到第一个指定了 view 的条目时停止,因此最好让你的 URL 配置从复杂的正则过渡到简单的正则,这样能确保 resolver 不会首先匹配 到简单的那一个而返回错误的 view function。

如果没有找到匹配的条目,resolver 会产生 django.core.urlresolvers.Resolver404 异常,它是 django.http.Http404 例 外的子类。后面我们会知道它是如何处理的。

6、 开始调用View中相应的视图函数或基于类的视图。

7、View进行一些处理,如通过模型Models返回数据。

8、如果需要,Views可以创建一个额外的Context,Context被当做变量传给Template。

9、Template渲染输出

10、渲染后的输出被返回到View

11、HTTPResponse被发送到Response Middlewares

12、Response Middlewares对response进行特定的处理,然后返回一个新的response

13、Response返回呈现给用户

14、一旦 middleware完成了最后环节,处理器将发送一个信号 request_finished,订阅这个信号的事件会清空并释放任何使用中的资源。比如,Django 的 request_finished 的订阅者subscriber会关闭所有数据库连接。

15、所有流程至此已经全部完成。

下面是处理器的源代码:

class WSGIHandler(base.BaseHandler):
        initLock = Lock()
        request_class = WSGIRequest #创建 WSGIRequest

        def __call__(self, environ, start_response):
                # Set up middleware if needed. We couldn't do this earlier, because
                # settings weren't available.
                if self._request_middleware is None:
                        with self.initLock:
                                try:
                                        # Check that middleware is still uninitialized.
                                        if self._request_middleware is None:
                                                self.load_middleware()
                                except:
                                        # Unload whatever middleware we got
                                        self._request_middleware = None
                                        raise

                set_script_prefix(get_script_name(environ))
                signals.request_started.send(sender=self.__class__, environ=environ)
                try:
                        request = self.request_class(environ)
                except UnicodeDecodeError:
                        logger.warning('Bad Request (UnicodeDecodeError)',
                                exc_info=sys.exc_info(),
                                extra={
                                        'status_code': 400,
                                }
                        )
                        response = http.HttpResponseBadRequest()
                else:
                        response = self.get_response(request)

                response._handler_class = self.__class__

                status = '%s %s' % (response.status_code, response.reason_phrase)
                response_headers = [(str(k), str(v)) for k, v in response.items()]
                for c in response.cookies.values():
                        response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
                start_response(force_str(status), response_headers)
                if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
                        response = environ['wsgi.file_wrapper'](response


    
.file_to_stream)
                return respons

异常情况:

如果 view 函数,或者其中的什么东西,发生了异常,那么 get_response将遍历它的 _exception_middleware 实例变量并呼叫那里的每个方法,传入 HttpResponse 和这个 exception 作为参数。如果顺利,最后会实例化,并返回一个 HttpResponse 。

这时候有可能还是没有得到一个 HttpResponse,这可能有几个原因:

view 并没有返回内容。 view 可能抛出了异常,但middleware没有 能处理它。 一个 middleware 方法试图处理一个异常时,自己又产生了一个异常。

处理器会做些相应的异常处理,如404,403,500等等,具体可以看上面的源代码。

里面有些地方是参考其他博客文章,但忘了地址了。如有原作者看到,请给予提示,谢谢。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/1673
 
3231 次点击  
文章 [ 1 ]  |  最新文章 8 年前
Py站长
Reply   •   1 楼
Py站长    8 年前

好文