WSGI初探
web伺服器和web框架
web伺服器即是用來接受客戶端請求,建立連線的程式, web框架則是用來處理業
務邏輯的,比如可以有很多的伺服器nginx
,apche
,uWSGI也可以有很多的框
架,django,flask,那這些東西如何搭配就會有問題,那麼這個問題的解決方就是
WSGI。
所以WSGI 就如其名是一個閘道器介面,提供伺服器和框架之間資料轉發的一 個介面,要通過這個介面當然就需要一定的規範。下面就是這種規範的具體內容
WSGI
在PEP 333 中的摘要給出,
This document specifies a proposed standard interface between web servers and Python web applications or frameworks,to promote web application portability across a variety of web servers.
也就是說 WSGI 是指定Web伺服器與Python Web應用程式或框架之間的標準介面, 以促進Web應用程式在各種Web伺服器之間的可移植性。
而且由於早期的框架和伺服器並不支援WSGI,而為了推廣WSGI,WSGI 就必須簡單易於實現,使得框架作者的實現成本降低。
django 中的WSGI
在django中的 wsgi.py 可以看到它是通過get_application()返回WSIGHandlers()
而在WSIGHandlers中實現了__call__
使得其被呼叫時返回response
,
其中兩個引數是必須的 environ
,start_response
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
複製程式碼
WSGI應用端
application 端的協議就是這樣的,這個api只需要兩個引數,可以看到是非
常簡單的,上面是框架中的東西,PEP 333
,中給出了一個更簡單的 事例,下面
對該事例進行了修改
def simple_app(environ,start_response):
stdout = "Hello world!"
h = sorted(environ.items())
for k,v in h:
stdout += k + '=' + repr(v) + "\r\n"
print(start_response)
start_response("200 OK",[('Content-Type','text/plain; charset=utf-8')])
return [stdout.encode("utf-8")]
複製程式碼
上面的程式碼就算一個滿足WSGI的Web應用程式,只要接收兩個引數即可,看起來很 像是API,其實它的確可以是當作API來用的但是這是給框架開發者使用的,
WSGI是面向框架、伺服器開發者的工具,而不是為應用開發者直接提供支援的。
WSGI服務端
下面通過標準庫中的wsgiref.simple_server
來實現一個簡單的伺服器,開啟之
後即可,通過網頁訪問本地埠8000得到請求
from wsgiref.simple_server import make_server
httpd = make_server('',8000,simple_app)
print('Serving HTTP on port 8000...')
httpd.serve_forever()
複製程式碼
當從HTTP客戶端收到一個請求,伺服器就呼叫simple_app去做邏輯處理並返回處理 的結果集。
中介軟體
中介軟體有著如下功能
- 在重寫environ之後,相應地根據目標URL把請求發到對應的應用物件。
- 允許多個應用或者框架並行允許。
- 通過網路來轉發請求和相應,實現負載均衡和遠端處理。
- 對內容進行後續處理,比如應用XSL樣式表
在web伺服器和應用程式之間存在著中介軟體,在的django中存在的中介軟體去處理請求 檢視,響應,模板,和異常,層層的包裹而形成了中介軟體棧(middleware stack)
self._request_middleware = []
self._view_middleware = []
self._template_response_middleware = []
self._response_middleware = []
self._exception_middleware = []
複製程式碼
那麼這些中介軟體在出入棧的過程中,中介軟體的位置就成立相對位置,對伺服器他是 應用,對於應用則他是服務.