zoukankan      html  css  js  c++  java
  • django 处理请求

    本文基于 django runsever

    • 入口
      • 执行 python manage.py runserver
        • 调用 django.core.management.commands.runserver.Command.handle
        • 文件 runserver.py(django/core/management/commands/runserver.py)
    • 启动 TCP server
      • 从上面 handle 会进入 django.core.servers.basehttp.run
    # 其中 server_cls 为 WSGIServer
    def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
        server_address = (addr, port)
        if threading:
            httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
        else:
            httpd_cls = server_cls
        httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
        if threading:
            # ThreadingMixIn.daemon_threads indicates how threads will behave on an
            # abrupt shutdown; like quitting the server by the user or restarting
            # by the auto-reloader. True means the server will not wait for thread
            # termination before it quits. This will make auto-reloader faster
            # and will prevent the need to kill the server manually if a thread
            # isn't terminating correctly.
            httpd.daemon_threads = True
        # wsgi_handler 为 settings.WSGI_APPLICATION 一般为 product_name/wsgi.py 中的 application
        httpd.set_app(wsgi_handler) # httpd_cls.application = application 在后面 get_app 方法中会获取到
        httpd.serve_forever()
    
    • 进入 server_forever
    # socketserver.BaseServer.serve_forever
        def serve_forever(self, poll_interval=0.5):
            """Handle one request at a time until shutdown.
    
            Polls for shutdown every poll_interval seconds. Ignores
            self.timeout. If you need to do periodic tasks, do them in
            another thread.
            """
            self.__is_shut_down.clear()
            try:
                # XXX: Consider using another file descriptor or connecting to the
                # socket to wake this up instead of polling. Polling reduces our
                # responsiveness to a shutdown request and wastes cpu at all other
                # times.
                with _ServerSelector() as selector:
                    selector.register(self, selectors.EVENT_READ)
    
                    while not self.__shutdown_request:
                        ready = selector.select(poll_interval)
                        # bpo-35017: shutdown() called during select(), exit immediately.
                        if self.__shutdown_request:
                            break
                        if ready:
                            self._handle_request_noblock()
    
                        self.service_actions()
            finally:
                self.__shutdown_request = False
                self.__is_shut_down.set()
    
    • 接下来进入 self._handle_request_noblock()
    # socketserver.BaseServer._handle_request_noblock
        def _handle_request_noblock(self):
            """Handle one request, without blocking.
    
            I assume that selector.select() has returned that the socket is
            readable before this function was called, so there should be no risk of
            blocking in get_request().
            """
            try:
                request, client_address = self.get_request()
            except OSError:
                return
            if self.verify_request(request, client_address):
                try:
                    self.process_request(request, client_address)
                except Exception:
                    self.handle_error(request, client_address)
                    self.shutdown_request(request)
                except:
                    self.shutdown_request(request)
                    raise
            else:
                self.shutdown_request(request)
    

    其中 request, client_address = self.get_request(), 这时候 request 还只是一个 socket 对象

    # socketserver.TCPServer.get_request
        def get_request(self):
            """Get the request and client address from the socket.
    
            May be overridden.
    
            """
            return self.socket.accept()
    
    • 处理请求 self.process_request(request, client_address)
    # socketserver.BaseServer.process_request
        def process_request(self, request, client_address):
            """Call finish_request.
    
            Overridden by ForkingMixIn and ThreadingMixIn.
    
            """
            self.finish_request(request, client_address)
            self.shutdown_request(request)
    
    • 完成一个 request self.finish_request(request, client_address)
    # socketserver.BaseServer.finish_request
        def finish_request(self, request, client_address):
            """Finish one request by instantiating RequestHandlerClass."""
            self.RequestHandlerClass(request, client_address, self)
    

    其中 RequestHandlerClass 为 WSGIRequestHandler (django.core.servers.basehttp.WSGIRequestHandler)
    注意: 这时候 request 还只是一个 socket 对象 <class 'socket.socket'>

    • 实例化 handler socketserver.BaseRequestHandler
    # socketserver.BaseRequestHandler
        def __init__(self, request, client_address, server):
            self.request = request
            self.client_address = client_address
            self.server = server
            self.setup()
            try:
                self.handle()
            finally:
                self.finish()
    

    其中 self.handle

    # django.core.servers.basehttp.WSGIRequestHandler.handle
        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
    
    • 从请求中获取信息 self.handle_one_request()
    # django.core.servers.basehttp.WSGIRequestHandler.handle_one_request
        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())  # 对应上面的 set_app
    

    其中 ServerHandler 实例化中没有做特殊的操作

    # django.core.servers.basehttp.ServerHandler
    pass
    

    run

    # wsgiref.handlers.BaseHandler.run
    # application 则是上面的 get_app 拿到的结果
        def run(self, application):
            """Invoke the application"""
            # Note to self: don't move the close()!  Asynchronous servers shouldn't
            # call close() from finish_response(), so if you close() anywhere but
            # the double-error branch here, you'll break asynchronous servers by
            # prematurely closing.  Async servers must return from 'run()' without
            # closing if there might still be output to iterate over.
            try:
                self.setup_environ()
                self.result = application(self.environ, self.start_response)
                self.finish_response()
            except:
                try:
                    self.handle_error()
                except:
                    # If we get an error handling an error, just give up already!
                    self.close()
                    raise   # ...and let the actual server figure it out.
    

    调用 handler 的 __call__

    • 上面的 application 其实就是 product/wsgi.py 中的 application 最终拿到的是 WSGIHandler 的一个实例
    # django.core.handlers.wsgi.WSGIHandler
    class WSGIHandler(base.BaseHandler):
        request_class = WSGIRequest
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.load_middleware()
    
        def __call__(self, environ, start_response):
            set_script_prefix(get_script_name(environ))
            signals.request_started.send(sender=self.__class__, environ=environ) # 发送 request_started 信号
            request = self.request_class(environ) # 实例化 WSGIRequest 得到 django 中 view 中真实的 request
            response = self.get_response(request) # 获取 response 会进入 middleware
    
            response._handler_class = self.__class__
    
            status = '%d %s' % (response.status_code, response.reason_phrase)
            response_headers = list(response.items())
            for c in response.cookies.values():
                response_headers.append(('Set-Cookie', c.output(header='')))
            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
    
    • 实例化 Request
    # django.core.handlers.wsgi.WSGIRequest
    pass
    
    • 获取 response
    # django.core.handlers.base.BaseHandler.get_response
        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 the exception handler returns a TemplateResponse that has not
            # been rendered, force it to be rendered.
            if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
                response = response.render()
    
            if response.status_code >= 400:
                log_response(
                    '%s: %s', response.reason_phrase, request.path,
                    response=response,
                    request=request,
                )
    
            return response
    

    接着回到 run

    • 关注下 self.finish_response()
    # wsgiref.handlers.BaseHandler.finish_response
        def finish_response(self):
            """Send any iterable data, then close self and the iterable
    
            Subclasses intended for use in asynchronous servers will
            want to redefine this method, such that it sets up callbacks
            in the event loop to iterate over the data, and to call
            'self.close()' once the response is finished.
            """
            try:
                if not self.result_is_file() or not self.sendfile():
                    for data in self.result:
                        self.write(data)
                    self.finish_content()
            finally:
                self.close()
    
    # 其中  self.write
    # wsgiref.handlers.BaseHandler.write
        def write(self, data):
            """'write()' callable as specified by PEP 3333"""
    
            assert type(data) is bytes, 
                "write() argument must be a bytes instance"
    
            if not self.status:
                raise AssertionError("write() before start_response()")
    
            elif not self.headers_sent:
                # Before the first output, send the stored headers
                self.bytes_sent = len(data)    # make sure we know content-length
                self.send_headers()
            else:
                self.bytes_sent += len(data)
    
            # XXX check Content-Length and truncate if too many bytes written?
            self._write(data)
            self._flush()
    
    # 其中 self._write
    # wsgiref.handlers.SimpleHandler._write
        def _write(self,data):
            result = self.stdout.write(data)
            if result is None or result == len(data):
                return
            from warnings import warn
            warn("SimpleHandler.stdout.write() should not do partial writes",
                DeprecationWarning)
            while True:
                data = data[result:]
                if not data:
                    break
                result = self.stdout.write(data)
    
    # 其中 result = self.stdout.write(data)
        def write(self, b):
            self._sock.sendall(b)
            with memoryview(b) as view:
                return view.nbytes
    
    
  • 相关阅读:
    react-router JS 控制路由跳转(转载)
    vue 将值存储到vuex 报错问题
    封装GetQueryString()方法来获取URL的value值(转载)
    vue 里面的watch 选项详解
    谷歌地图api 开发 (转载)
    es6 ...展开运算符
    关于localStorage 应用总结
    js 刷新当前页面会弹出提示框怎样将这个提示框去掉
    深入浅析JavaScript的API设计原则(转载)
    jQuery mouseover与mouseenter,mouseout与mouseleave的区别
  • 原文地址:https://www.cnblogs.com/twotigers/p/11357496.html
Copyright © 2011-2022 走看看