首先弄清下面幾個概念:
WSGI:全稱是Web Server Gateway Interface
,WSGI
不是服務器,python
模塊,框架,API
或者任何軟件,只是一種規範,描述web server
如何與web application
通訊的規範。server
和application
的規範在PEP 3333中有具體描述。要實現WSGI協議,必須同時實現web server和web application,當前運行在WSGI
協議之上的web
框架有Bottle
, Flask
, Django
。
uwsgi:與WSGI
同樣是一種通訊協議,是uWSGI
服務器的獨佔協議,用於定義傳輸信息的類型(type of information
),每個uwsgi packet
前4byte
爲傳輸信息類型的描述,與WSGI協議是兩種東西,聽說該協議是fcgi
協議的10倍快。
uWSGI:是一個web
服務器,實現了WSGI
協議、uwsgi
協議、http
協議等。html
WSGI
協議主要包括server
和application
兩部分:python
WSGI server
負責從客戶端接收請求,將request
轉發給application
,將application
返回的response
返回給客戶端;WSGI application
接收由server
轉發的request
,處理請求,並將處理結果返回給server
。application
中能夠包括多個棧式的中間件(middlewares
),這些中間件須要同時實現server與application,所以能夠在WSGI服務器與WSGI應用之間起調節做用:對服務器來講,中間件扮演應用程序,對應用程序來講,中間件扮演服務器。WSGI
協議實際上是定義了一種server
與application
解耦的規範,便可以有多個實現WSGI server
的服務器,也能夠有多個實現WSGI application
的框架,那麼就能夠選擇任意的server
和application
組合實現本身的web
應用。例如uWSGI
和Gunicorn
都是實現了WSGI server
協議的服務器,Django
,Flask
是實現了WSGI application
協議的web
框架,能夠根據項目實際狀況搭配使用。nginx
像Django
,Flask
框架都有本身實現的簡單的WSGI server
,通常用於服務器調試,生產環境下建議用其餘WSGI server
。web
以Django
爲例,分析一下WSGI
協議的具體實現過程。django
WSGI application
應該實現爲一個可調用對象,例如函數、方法、類(包含**call**
方法)。須要接收兩個參數:瀏覽器
environment
(編碼中多簡寫爲environ
、env
)HTTP status
)、響應頭(HTTP headers
)的回調函數經過回調函數將響應狀態和響應頭返回給server
,同時返回響應正文(response body
),響應正文是可迭代的、幷包含了多個字符串。下面是Django
中application
的具體實現部分:服務器
class WSGIHandler(base.BaseHandler): initLock = Lock() request_class = WSGIRequest def __call__(self, environ, start_response): # 加載中間件 if self._request_middleware is None: with self.initLock: try: # Check that middleware is still uninitialized. if self._request_middleware is None: self.load_middleware() except: # Unload whatever middleware we got self._request_middleware = None raise set_script_prefix(get_script_name(environ)) # 請求處理以前發送信號 signals.request_started.send(sender=self.__class__, environ=environ) try: request = self.request_class(environ) except UnicodeDecodeError: logger.warning('Bad Request (UnicodeDecodeError)', exc_info=sys.exc_info(), extra={'status_code': 400,}) response = http.HttpResponseBadRequest() else: response = self.get_response(request) response._handler_class = self.__class__ status = '%s %s' % (response.status_code, response.reason_phrase) response_headers = [(str(k), str(v)) for k, v in response.items()] for c in response.cookies.values(): response_headers.append((str('Set-Cookie'), str(c.output(header='')))) # server提供的回調方法,將響應的header和status返回給server start_response(force_str(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
能夠看出application
的流程包括:cookie
get_response()
方法處理當前請求,該方法的的主要邏輯是經過urlconf
找到對應的view
和callback
,按順序執行各類middleware
和callback
。server
傳入的start_response()
方法將響應header
與status
返回給server
。負責獲取http
請求,將請求傳遞給WSGI application
,由application
處理請求後返回response
。以Django
內建server
爲例看一下具體實現。
經過runserver
運行django
項目,在啓動時都會調用下面的run
方法,建立一個WSGIServer
的實例,以後再調用其serve_forever()
方法啓動服務。網絡
def run(addr, port, wsgi_handler, ipv6=False, threading=False): server_address = (addr, port) if threading: httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {}) else: httpd_cls = WSGIServer # 這裏的wsgi_handler就是WSGIApplication httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) if threading: httpd.daemon_threads = True httpd.set_app(wsgi_handler) httpd.serve_forever()
下面表示WSGI server
服務器處理流程中關鍵的類和方法。mvc
xiong (2).png-93.7kB
WSGIServer
run()
方法會建立
WSGIServer
實例,主要做用是接收客戶端請求,將請求傳遞給
application
,而後將
application
返回的
response
返回給客戶端。
HTTP
請求的handler
:WSGIRequestHandler
類set_app
和get_app
方法設置和獲取WSGIApplication
實例wsgi_handler
handler_request
方法,會建立WSGIRequestHandler
實例處理http請求。WSGIServer
中get_request
方法經過socket
接受請求數據WSGIRequestHandler
WSGIServer
在調用handle_request
時建立實例,傳入request
、cient_address
、WSGIServer
三個參數,__init__
方法在實例化同時還會調用自身的handle
方法handle
方法會建立ServerHandler
實例,而後調用其run
方法處理請求ServerHandler
WSGIRequestHandler
在其handle
方法中調用run
方法,傳入self.server.get_app()
參數,獲取WSGIApplication
,而後調用實例(__call__
),獲取response
,其中會傳入start_response
回調,用來處理返回的header
和status
。application
獲取response
之後,經過finish_response
返回response
WSGIHandler
WSGI
協議中的application
,接收兩個參數,environ
字典包含了客戶端請求的信息以及其餘信息,能夠認爲是請求上下文,start_response
用於發送返回status
和header
的回調函數雖然上面一個WSGI server
涉及到多個類實現以及相互引用,但其實原理仍是調用WSGIHandler
,傳入請求參數以及回調方法start_response()
,並將響應返回給客戶端。
django
的simple_server.py
模塊實現了一個簡單的HTTP
服務器,並給出了一個簡單的demo
,能夠直接運行,運行結果會將請求中涉及到的環境變量在瀏覽器中展現出來。
其中包括上述描述的整個http
請求的全部組件:
ServerHandler
, WSGIServer
, WSGIRequestHandler
,以及demo_app
表示的簡易版的WSGIApplication
。
能夠看一下整個流程:
if __name__ == '__main__': # 經過make_server方法建立WSGIServer實例 # 傳入建議application,demo_app httpd = make_server('', 8000, demo_app) sa = httpd.socket.getsockname() print("Serving HTTP on", sa[0], "port", sa[1], "...") import webbrowser webbrowser.open('http://localhost:8000/xyz?abc') # 調用WSGIServer的handle_request方法處理http請求 httpd.handle_request() # serve one request, then exit httpd.server_close() def make_server( host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler ): """Create a new WSGI server listening on `host` and `port` for `app`""" server = server_class((host, port), handler_class) server.set_app(app) return server # demo_app可調用對象,接受請求輸出結果 def demo_app(environ,start_response): from io import StringIO stdout = StringIO() print("Hello world!", file=stdout) print(file=stdout) h = sorted(environ.items()) for k,v in h: print(k,'=',repr(v), file=stdout) start_response("200 OK", [('Content-Type','text/plain; charset=utf-8')]) return [stdout.getvalue().encode("utf-8")]
demo_app()
表示一個簡單的WSGI application實現,經過make_server()
方法建立一個WSGIServer
實例,調用其handle_request()
方法,該方法會調用demo_app()
處理請求,並最終返回響應。
uWSGI
旨在爲部署分佈式集羣的網絡應用開發一套完整的解決方案。主要面向web
及其標準服務。因爲其可擴展性,可以被無限制的擴展用來支持更多平臺和語言。uWSGI
是一個web
服務器,實現了WSGI
協議,uwsgi
協議,http
協議等。
uWSGI
的主要特色是:
app
管理app
的性能和瓶頸)uWSGI
服務器本身實現了基於uwsgi
協議的server
部分,咱們只須要在uwsgi
的配置文件中指定application
的地址,uWSGI
就能直接和應用框架中的WSGI application
通訊。
參考資料:
作python Web開發你要理解:WSGI & uwsgi
WSGI & uwsgi
WSGI Tutorial
打造mvc框架之wsgi協議的優缺點及接口實現
Nginx和uWSGI通訊機制
理解Python WSGI