WSGI協(xié)議
首先弄清下面幾個概念:
WSGI:全稱是Web Server Gateway Interface,WSGI不是服務(wù)器,python模塊,框架,API或者任何軟件,只是一種規(guī)范,描述web server如何與web application通信的規(guī)范。server和application的規(guī)范在PEP 3333中有具體描述。要實(shí)現(xiàn)WSGI協(xié)議,必須同時實(shí)現(xiàn)web server和web application,當(dāng)前運(yùn)行在WSGI協(xié)議之上的web框架有Bottle, Flask, Django。
uwsgi:與WSGI一樣是一種通信協(xié)議,是uWSGI服務(wù)器的獨(dú)占協(xié)議,用于定義傳輸信息的類型(type of information),每一個uwsgi packet前4byte為傳輸信息類型的描述,與WSGI協(xié)議是兩種東西,據(jù)說該協(xié)議是fcgi協(xié)議的10倍快。
uWSGI:是一個web服務(wù)器,實(shí)現(xiàn)了WSGI協(xié)議、uwsgi協(xié)議、http協(xié)議等。
WSGI協(xié)議主要包括server和application兩部分:
WSGI server負(fù)責(zé)從客戶端接收請求,將request轉(zhuǎn)發(fā)給application,將application返回的response返回給客戶端; WSGI application接收由server轉(zhuǎn)發(fā)的request,處理請求,并將處理結(jié)果返回給server。application中可以包括多個棧式的中間件(middlewares),這些中間件需要同時實(shí)現(xiàn)server與application,因此可以在WSGI服務(wù)器與WSGI應(yīng)用之間起調(diào)節(jié)作用:對服務(wù)器來說,中間件扮演應(yīng)用程序,對應(yīng)用程序來說,中間件扮演服務(wù)器。WSGI協(xié)議其實(shí)是定義了一種server與application解耦的規(guī)范,即可以有多個實(shí)現(xiàn)WSGI server的服務(wù)器,也可以有多個實(shí)現(xiàn)WSGI application的框架,那么就可以選擇任意的server和application組合實(shí)現(xiàn)自己的web應(yīng)用。例如uWSGI和Gunicorn都是實(shí)現(xiàn)了WSGI server協(xié)議的服務(wù)器,Django,F(xiàn)lask是實(shí)現(xiàn)了WSGI application協(xié)議的web框架,可以根據(jù)項(xiàng)目實(shí)際情況搭配使用。

像Django,F(xiàn)lask框架都有自己實(shí)現(xiàn)的簡單的WSGI server,一般用于服務(wù)器調(diào)試,生產(chǎn)環(huán)境下建議用其他WSGI server。
WSGI協(xié)議的實(shí)現(xiàn)
以Django為例,分析一下WSGI協(xié)議的具體實(shí)現(xiàn)過程。
django WSGI application
WSGI application應(yīng)該實(shí)現(xiàn)為一個可調(diào)用對象,例如函數(shù)、方法、類(包含`call`方法)。需要接收兩個參數(shù):
一個字典,該字典可以包含了客戶端請求的信息以及其他信息,可以認(rèn)為是請求上下文,一般叫做environment(編碼中多簡寫為environ、env) 一個用于發(fā)送HTTP響應(yīng)狀態(tài)(HTTP status )、響應(yīng)頭(HTTP headers)的回調(diào)函數(shù)通過回調(diào)函數(shù)將響應(yīng)狀態(tài)和響應(yīng)頭返回給server,同時返回響應(yīng)正文(response body),響應(yīng)正文是可迭代的、并包含了多個字符串。下面是Django中application的具體實(shí)現(xiàn)部分:
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)) # 請求處理之前發(fā)送信號 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提供的回調(diào)方法,將響應(yīng)的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
新聞熱點(diǎn)
疑難解答
圖片精選