天天看點

django架構--底層架構

目錄

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

web

服務應該至少包含兩個子產品:

web

伺服器和

web

應用程式,兩個子產品在功能和代碼上解耦。

web

伺服器負責處理

socket

調用、

http

資料解析和封裝等底層操作。

web

應用程式負責業務處理、資料增删改查、頁面渲染/生成等高層操作。

web

伺服器一旦接收到

http

請求,經過自身的解析後就會調用

web

應用程式來處理業務邏輯,并得到

web

應用程式的傳回值,再經過自身的封裝發送給用戶端。

web

web

應用程式之間需要定義一個接口規則,這也叫協定,用于明确兩者之間以什麼樣的形式互動資料。即:

web

伺服器應該以什麼樣的形式調用web應用程式,而

web

應用程式又應該定義成什麼形式。

python

下規定的

web

服務的接口規則叫做

wsgi

wsgi

協定對于

server

application

的接口定義如下:

對于

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',]           

隻要是遵從如上形式進一步封裝

server

application

的,均稱為實作了

wsgi

協定的

server/application

python

内置提供了一個

wsigref

子產品用于提供

server

,但是隻能用于開發測試,

django

架構就是使用此子產品作為它的

server

部分,也就說,實際生産中的

server

部分,還需要使用其他子產品來實作。

任何

web

架構,可能沒有實作

server

部分或者隻實作一個簡單的

server

,但是,

web

架構肯定實作了

application

部分。

application

部分完成了對一次請求的全流程處理,其中各環節都可以提供豐富的功能,比如請求和響應對象的封裝、

model/template

的實作、中間件的實作等,讓我們可以更加細粒度的控制請求/響應的流程。

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

子產品是基于

python

wsgiref

子產品中的

simple_server

,每次

django

的啟動都會執行如下

run

函數。

run

函數中會執行

serve_forever

,此步驟将會啟動

socket_server

的無限循環,此時就可以循環提供請求服務,每次用戶端請求到來,服務端就執行

django

提供的

application

子產品。

django

server

的啟動----

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

子產品是通過

WSGIHandler

的一個執行個體來提供的,此執行個體可以被

call

,然後根據

wsgi

的接口規則傳入

environ

start_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

架構,精通一門架構的實作原理和設計理念。