web服務器便是用來接受客戶端請求,創建鏈接的程序, web框架則是用來處理業 務邏輯的,好比能夠有不少的服務器nginx
,apche
,uWSGI也能夠有不少的框 架,django,flask,那這些東西如何搭配就會有問題,那麼這個問題的解決方就是 WSGI。php
因此WSGI 就如其名是一個網關接口,提供服務器和框架之間數據轉發的一 個接口,要經過這個接口固然就須要必定的規範。下面就是這種規範的具體內容python
在PEP 333 中的摘要給出,nginx
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.web
也就是說 WSGI 是指定Web服務器與Python Web應用程序或框架之間的標準接口, 以促進Web應用程序在各類Web服務器之間的可移植性。django
並且因爲早期的框架和服務器並不支持WSGI,而爲了推廣WSGI, WSGI 就必須簡單易於實現,使得框架做者的實現成本下降。flask
在django中的 wsgi.py 能夠看到它是經過get_application()返回WSIGHandlers() 而在WSIGHandlers中實現了__call__
使得其被調用時返回response
,api
其中兩個參數是必須的 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
複製代碼
application 端的協議就是這樣的,這個api只須要兩個參數,能夠看到是非 常簡單的,上面是框架中的東西,PEP 333
,中給出了一個更簡單的 事例,下面 對該事例進行了修改cookie
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是面向框架、服務器開發者的工具,而不是爲應用開發者直接提供支持的。
下面經過標準庫中的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去作邏輯處理並返回處理 的結果集。
中間件有着以下功能
在web服務器和應用程序之間存在着中間件,在的django中存在的中間件去處理請求 視圖,響應,模板,和異常,層層的包裹而造成了中間件棧(middleware stack)
self._request_middleware = []
self._view_middleware = []
self._template_response_middleware = []
self._response_middleware = []
self._exception_middleware = []
複製代碼
那麼這些中間件在出入棧的過程當中,中間件的位置就成立相對位置,對服務器他是 應用,對於應用則他是服務.