django框架--底層架構
目錄
- 二、對於wsgi協議的理解
- 三、自定義一個簡單的基於wsgi協議的web框架
- 四、django中的server實現
- 五、django中的application實現
- 六、django的底層呼叫鏈
零、參考
ofollow,noindex" target="_blank">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
服務的介面規則叫做 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
的實現、中介軟體的實現等,讓我們可以更加細粒度的控制請求/響應的流程。
三、自定義一個簡單的基於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
模組。
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實現
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
框架,精通一門框架的實現原理和設計理念。