django框架--底層架構
目錄
- 零、參考
- 一、對於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
服務的接口規則叫做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
框架,精通一門框架的實現原理和設計理念。
django框架--底層架構