WSGI(Web 服務(wù)器網(wǎng)關(guān)接口)是python中所定義的Web Server和Web APP之間或框架之間的接口標準規(guī)范。當使用 Python 進行 web 開發(fā)時,要深刻理解 Django、Flask、Tornado等 web 框架,WSGI是你繞不過去的檻兒。WSGI接口規(guī)范的目的就是規(guī)范Web服務(wù)器與Web應(yīng)用之間的交互,在協(xié)議之間進行轉(zhuǎn)換。- Web服務(wù)器(Server): 監(jiān)聽某個端口的http服務(wù)器
- Web應(yīng)用程序(APP): 指的是可以被調(diào)用的一個對象,一般指的是一個函數(shù) 或者 包含一個
__call__ 方法的類的實例 - Web中間件(Middleware):處于服務(wù)器和應(yīng)用中間,起到承接的作用,用Python的術(shù)語來說,中間件就類似于一個裝飾器
#這是一個appdef app(environ, start_response): return [] def middleware(environ, start_response): #這里編寫中間件的代碼 return app(environ, start_response) django 整個項目實際上也是這三部分組成,我們在執(zhí)行python manage.py runserver 的時候,
- 就首先啟動了一個8000端口的http服務(wù)器(這個就是Web服務(wù)器)
- 然后 django里面的中間件(這個就是上述所說的Web中間件),這個是定義在
settings.py 文件的 MIDDLEWARE - 最后 django加載里面的app(這個就是上述所說的Web應(yīng)用程序),這個是定義在
settings.py 文件的 INSTALLED_APPS
WSGI App介紹WSGI APP是一個可調(diào)用的對象(callable object),常用的可調(diào)用的對象有三種:def app(environ, start_response): 這是一個app return [] 2.一個實現(xiàn)__call__() 方法的類的實例:class app:
def __call__(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return []
- 接收兩個參數(shù)
environ 和start_response : environ 是一個字典,里面儲存了HTTP request的所有內(nèi)容。在django里面,通常會把environ 封裝成為一個request。start_response 是一個WSGI Server(http 服務(wù)器)傳遞過來的函數(shù),用于將response header, status傳遞給Server。start_response(status, headers) , 它的作用是返回狀態(tài)碼 以及 頭部信息, status必須是一個字符串,格式是 “狀態(tài)碼 + 說明”。- headers 是一個數(shù)組,按照 [(key, value), (key, value) ] 這樣的格式來組織。
- 它需要返回一個可迭代的值,用于將response body傳遞給Server。
["hello world", "baby"]
WSGI Server介紹WSGI Server可以理解為就是一個實現(xiàn)了wsgi協(xié)議的http服務(wù)器,使用wsgi協(xié)議的方式來調(diào)用WSGI APP。1.http 服務(wù)器:這里具體的代碼就不寫了,大概就是socket = eventlet.listen(('localhost', '8000'), backlog = 10) 定義一個wsgi http服務(wù)器server = eventlet.spawn(event.wsgi.server, socket, app) 把service 和 app進行綁定 def run(application): #服務(wù)器程序調(diào)用應(yīng)用程序 environ = {}#設(shè)定參數(shù) def start_response(status, headers): #設(shè)定狀態(tài)和頭部參數(shù)的回調(diào)函數(shù) pass
result = application(environ, start_response)#調(diào)用APP的__call__函數(shù)(這里APP是一個類) def write(data): # 這是把響應(yīng)發(fā)到前端的函數(shù) pass def data in result: # 迭代訪問,把響應(yīng)發(fā)到前端 write(data)
- 設(shè)定app所需要的參數(shù)(environ,start_response)
- 迭代訪問app的返回結(jié)果(response body),并傳給客戶端
但實際上已經(jīng)有很多已經(jīng)封裝好的WSGI Server供我們使用,只需簡單的將APP與一些其他的參數(shù)綁定來創(chuàng)建一個Server,而這個Server會將它接收到的request傳遞給綁定的APP。from wsgiref.simple_server import make_server
# 定義我們一個最簡單的app def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [b'<h1>Hello, web!</h1>']
# 創(chuàng)建一個服務(wù)器,IP地址為空,端口是8000,處理函數(shù)是application: httpd = make_server('', 8000, application) print('Serving HTTP on port 8000...') # 開始監(jiān)聽HTTP請求: httpd.serve_forever() 這里我們已經(jīng)自己編寫了一個最基礎(chǔ)的web框架,是不是很激動,django的本質(zhì)就是這樣的一種形式,是不是感覺發(fā)現(xiàn)了新大陸。
WSGI Middleware介紹middleware 的概念沒有appllication 和server 那么容易理解。假設(shè)一個符合application 標準的可調(diào)用對象,它接受可調(diào)用對象作為參數(shù),返回一個可調(diào)用對象的對象。那么對于server 來說,它是一個符合標準的可調(diào)用對象,因此是application 。而對于application 來說,它可以調(diào)用application ,因此是server 。這樣的可調(diào)用對象稱為middleware 。middleware 的概念非常接近decorator 。中間件對于app來說,它是一個service. 但是對于service來說,它確實一個app。文字說的不清晰,還是用代碼來說比較好。# 這是一個標準的application object def index(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return ['index page']
# 這是一個標準的application object def hello(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return ['hello page']
# 這是一個標準的application object def not_found(environ, start_response): start_response('404 NOT FOUND', [('Content-Type', 'text/plain')]) return ['Not Found Page']
###上面我們定義了三個app ### 然后我們定義一個中間件 middleware,這個中間件的形式是跟app是一樣的 def application(environ, start_response): path = environ.get('PATH_INFO', '').lstrip('/') #這句代碼是獲取url
urls = [ # 這里定義路由 ('index', index), ('hello', hello) ]
for item in urls: # 這里根據(jù)路由,執(zhí)行不同的app if item[0] == path: app = item[1] return app(environ, start_response) else: return not_found(environ, start_response) # 如果找不到,則執(zhí)行默認的app from wsgiref.simple_server import make_server
# 創(chuàng)建一個服務(wù)器,IP地址為空,端口是8000,處理函數(shù)是application: httpd = make_server('', 8000, application) httpd.serve_forever() 看到?jīng)]有,這個例子比上面的更加完善,利用中間件實現(xiàn)了路由的功能,把django最基礎(chǔ)的功能完整的展示出來 中間件除了路由之外,還可以做很多事情,最常見的還有:- 預(yù)處理 XSL 等相關(guān)數(shù)據(jù)
|