Django请求处理流程

2023-08-19 09:47:27 浏览数 (2)

源码地址:https://github.com/django/django

请求流

代码语言:javascript复制
Socketserver.py#StreamRequestHandler -> http/server.py#BaseHTTPRequestHandler -> wsgiref/simple_server.py#WSGIRequestHandler -> django/core/servers/basehttp.py#WSGIRequestHandler:

此时就进入到django库中了,那么接下来分析具体的流程。

Django处理逻辑

代码入口:django/core/servers/basehttp.py#WSGIRequestHandler.handle()

代码语言:javascript复制
def handle(self):
    self.close_connection = True
    self.handle_one_request()
    while not self.close_connection:
        self.handle_one_request()
    try:
        self.connection.shutdown(socket.SHUT_WR)
    except (socket.error, AttributeError):
        pass

这里很简单,就是处理一个请求,我们进入具体的处理函数:

代码语言:javascript复制
def handle_one_request(self):
    """Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
    self.raw_requestline = self.rfile.readline(65537)
    if len(self.raw_requestline) > 65536:
        self.requestline = ''
        self.request_version = ''
        self.command = ''
        self.send_error(414)
        return

    if not self.parse_request(): # An error code has been sent, just exit
        return

    handler = ServerHandler(
        self.rfile, self.wfile, self.get_stderr(), self.get_environ()
    )
    handler.request_handler = self # backpointer for logging & connection closing
    handler.run(self.server.get_app())

注意这里的get_app,就是wsgi规范中定义的application,在这里就是StaticFilesHandler,run方法里面实际就是调用了改app对象:

代码语言:javascript复制
try:
    self.setup_environ()
    self.result = application(self.environ, self.start_response)
    self.finish_response()
 except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):
    # We expect the client to close the connection abruptly from time
    # to time.
    return

在python中,第一个可调用对象进行调用,实际上就是执行其__call__方法:

代码语言:javascript复制
def __call__(self, environ, start_response):
    if not self._should_handle(get_path_info(environ)):
        return self.application(environ, start_response)
    return super().__call__(environ, start_response)

这里可以看到,又是调用了其自己管理的app,也就是委托WSGIHandler这个app进行处理,同样的,也是执行的其__call__方法:

代码语言:javascript复制
def __call__(self, environ, start_response):
    set_script_prefix(get_script_name(environ))
    signals.request_started.send(sender=self.__class__, environ=environ)
    request = self.request_class(environ)
    response = self.get_response(request)

    response._handler_class = self.__class__

    status = '%d %s' % (response.status_code, response.reason_phrase)
    response_headers = [
        *response.items(),
        *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
    ]
    start_response(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 response

可以看到,这里将wsgi规范中的environ模型转换成了django自身的request模型,然后再传下去进行处理:

代码语言:javascript复制
def get_response(self, request):
    """Return an HttpResponse object for the given HttpRequest."""
    # Setup default url resolver for this thread
    set_urlconf(settings.ROOT_URLCONF)
    response = self._middleware_chain(request)
    response._closable_objects.append(request)
    if response.status_code >= 400:
        log_response(
            '%s: %s', response.reason_phrase, request.path,
            response=response,
            request=request,
        )
    return response

这里又调用了中间件链来处理请求,因为在wsgi的流程中,一个请求从请求入口到结果返回,中间会经过一系列的中间件过程,这些中间件实际上也是一个个的app

然后进入到django/core/handlers/base.py的_get_response()中:

代码语言:javascript复制
def _get_response(self, request):
"""
    Resolve and call the view, then apply view, exception, and
    template_response middleware. This method is everything that happens
    inside the request/response middleware.
    """
    response = None
if hasattr(request, 'urlconf'):
        urlconf = request.urlconf
        set_urlconf(urlconf)
        resolver = get_resolver(urlconf)
else:
        resolver = get_resolver()
    resolver_match = resolver.resolve(request.path_info)
    callback, callback_args, callback_kwargs = resolver_match
    request.resolver_match = resolver_match
# Apply view middleware
for middleware_method in self._view_middleware:
        response = middleware_method(request, callback, callback_args, callback_kwargs)
if response:
break
if response is None:
        wrapped_callback = self.make_view_atomic(callback)
try:
            response = wrapped_callback(request, *callback_args, **callback_kwargs)
except Exception as e:
            response = self.process_exception_by_middleware(e, request)

继续跟踪代码,最后我们会发现进入到了django/views/generic/base.py的as_view处理中:

代码语言:javascript复制
@classonlymethod
def as_view(cls, **initkwargs):
    """Main entry point for a request-response process."""
    for key in initkwargs:
        if key in cls.http_method_names:
            raise TypeError("You tried to pass in the %s method name as a "
                            "keyword argument to %s(). Don't do that."
                            % (key, cls.__name__))
        if not hasattr(cls, key):
            raise TypeError("%s() received an invalid keyword %r. as_view "
                            "only accepts arguments that are already "
                            "attributes of the class." % (cls.__name__, key))

    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.setup(request, *args, **kwargs)
        if not hasattr(self, 'request'):
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
        return self.dispatch(request, *args, **kwargs)
    view.view_class = cls
    view.view_initkwargs = initkwargs

    # take name and docstring from class
    update_wrapper(view, cls, updated=())

    # and possible attributes set by decorators
    # like csrf_exempt from dispatch
    update_wrapper(view, cls.dispatch, assigned=())
    return view

这里的as_view也就是我们在view控制类中经常使用到的,然后他通过一个分发器对请求进行处理:

代码语言:javascript复制
def dispatch(self, request, *args, **kwargs):
    """
    `.dispatch()` is pretty much the same as Django's regular dispatch,
    but with extra hooks for startup, finalize, and exception handling.
    """
    self.args = args
    self.kwargs = kwargs
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    self.headers = self.default_response_headers # deprecate?
    try:
        self.initial(request, *args, **kwargs)
    # Get the appropriate handler method
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(),
            self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        response = handler(request, *args, **kwargs)
    except Exception as exc:
        response = self.handle_exception(exc)
    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response

可以看到,这里通过请求的类型(get、post等)反射得到view类的具体方法,然后执行,最后就到了我们自己view类的具体方法中了。

0 人点赞