目錄
- 零、參考
- 一、對于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
伺服器負責處理
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

web
服務是基于
socket
的高層服務,是以
web
服務必須含有
web
伺服器這一子產品。
web
服務需要動态渲染資料,需要中間件來豐富功能,需要封裝和解析來處理資料,是以
web
web
應用程式這一子產品。
web
架構是一種工具集,封裝了各種功能的底層代碼,提供給我們友善開發的接口。但不論是哪一種架構,它們的底層原理基本都是一緻的。
應該深入學習、研究一個
web
架構,精通一門架構的實作原理和設計理念。