1. 程式人生 > >django框架--底層架構

django框架--底層架構

instead gist 處理 term str att nsh emp for

目錄

  • 零、參考
  • 一、對於web服務的理解
  • 二、對於wsgi協議的理解
  • 三、自定義一個簡單的基於wsgi協議的web框架
  • 四、django中的server實現
  • 五、django中的application實現
  • 六、django的底層調用鏈
  • 七、總結

零、參考

https://www.jianshu.com/p/679dee0a4193
https://www.letiantian.me/2015-09-10-understand-python-wsgi/

一、對於web服務的理解

web服務應該至少包含兩個模塊:web服務器和web應用程序,兩個模塊在功能和代碼上解耦。
web服務器負責處理socket調用、http

數據解析和封裝等底層操作。
web應用程序負責業務處理、數據增刪改查、頁面渲染/生成等高層操作。
web服務器一旦接收到http請求,經過自身的解析後就會調用web應用程序來處理業務邏輯,並得到web應用程序的返回值,再經過自身的封裝發送給客戶端。

二、對於wsgi協議的理解

web服務器和web應用程序之間需要定義一個接口規則,這也叫協議,用於明確兩者之間以什麽樣的形式交互數據。即:web服務器應該以什麽樣的形式調用web應用程序,而web應用程序又應該定義成什麽形式。

python下規定的web服務的接口規則叫做wsgiwsgi協議對於serverapplication的接口定義如下:

對於server調用規則的定義:

response = application(environ, start_response) 

對於application接口編碼的定義:

def application(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-Type', 'text/plain'),]
    start_response(status, response_headers)
    
    return [b'hello',]

只要是遵從如上形式進一步封裝serverapplication的,均稱為實現了wsgi協議的server/application

python內置提供了一個wsigref模塊用於提供server,但是只能用於開發測試,django框架就是使用此模塊作為它的server部分,也就說,實際生產中的server部分,還需要使用其他模塊來實現。

任何web框架,可能沒有實現server部分或者只實現一個簡單的server,但是,web框架肯定實現了application部分。application部分完成了對一次請求的全流程處理,其中各環節都可以提供豐富的功能,比如請求和響應對象的封裝、model/template的實現、中間件的實現等,讓我們可以更加細粒度的控制請求/響應的流程。

三、自定義一個簡單的基於wsgi協議的web框架

django框架的server部分由python內置的wsgiref模塊提供,我們只需要編寫application應用程序部分。

from wsgiref.simple_server import make_server

def app(environ, start_response):  # wsgi協議規定的application部分的編碼形式,可在此基礎上擴展
    status = '200 OK'
    respones_headers = []
    
    start_response(status, response_headers)
    return [b'hello',]

if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8080, app)
    httpd.serve_forever()

四、django中的server實現

django使用的底層server模塊是基於python內置的wsgiref模塊中的simple_server,每次django的啟動都會執行如下run函數。run函數中會執行serve_forever,此步驟將會啟動socket_server的無限循環,此時就可以循環提供請求服務,每次客戶端請求到來,服務端就執行django提供的application模塊。

djangoserver的啟動----django.core.servers.basehttp.py

"""
HTTP server that implements the Python WSGI protocol (PEP 333, rev 1.21).

Based on wsgiref.simple_server which is part of the standard library since 2.5.

This is a simple server for use in testing or debugging Django apps. It hasn't
been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE!
"""

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
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()

底層無限循環將作為web服務的主要驅動----socektserver.py

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)
                if ready:
                    self._handle_request_noblock()

                self.service_actions()
    finally:
        self.__shutdown_request = False
        self.__is_shut_down.set()

server對於application的調用----wsgiref.handlers.py

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.

五、django中的application實現

djangoapplication模塊是通過WSGIHandler的一個實例來提供的,此實例可以被call,然後根據wsgi的接口規則傳入environstart_response。所以本質上,django就是使用的內置python提供的wsgiref.simple_server再對application進行豐富的封裝。大部分的django編碼工作都在application部分。

application的編碼定義部分----django.core.handlers.wsgi.py

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 = 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 = 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

六、django的底層調用鏈

技術分享圖片

七、總結

web服務是基於socket的高層服務,所以web服務必須含有web服務器這一模塊。
web服務需要動態渲染數據,需要中間件來豐富功能,需要封裝和解析來處理數據,所以web服務必須含有web應用程序這一模塊。
web框架是一種工具集,封裝了各種功能的底層代碼,提供給我們方便開發的接口。但不論是哪一種框架,它們的底層原理基本都是一致的。
應該深入學習、研究一個web框架,精通一門框架的實現原理和設計理念。

django框架--底層架構