1. 為什么要研究WSGI
我之前在學習web開發時,往往都是根據MVT等架構直接寫所謂的“視圖”,使用其本身自帶的http服務器,當時就一直很好奇,為什么有了HTTP協議之后,還要研究WSGI協議,它到底有什么用?
由於“工作要緊”所以很多細枝末節的事情 都被安排到推遲,最終遲遲沒有研究
后來有個空閑時間的機會,終於可以靜下來研究WSGI
2. 說說WSGI與HTTP服務器之間的調用過程
2.1 瀏覽器請求動態頁面過程
看完上圖估計也就知道了所謂的WSGI到底有什么用,如果還是不明白,那我就通俗點說:
web服務器接收到瀏覽器發送過來的請求之后,需要將瀏覽器傳遞過來的很多數據(例如user-agent、cookie等)都要告訴你的“視圖”,因為只有“視圖”接收到數據,才能夠進一步處理,例如判斷是否登錄等
所以這就需要web服務器與“視圖”之間的傳遞,此時WSGI就是起到傳遞的作用,只不過這個傳遞的過程有些復雜 可以參考上圖2、3、4、6步驟
2.2 用個例子來說明WSGI
怎么在你剛建立的Web服務器上運行一個Django應用
和Flask應用
,如何不做任何改變而適應不同的web架構呢?
在以前,選擇 Python web 架構
會受制於可用的web服務器
,反之亦然。如果架構和服務器可以協同工作,那就好了:
但有可能面對(或者曾有過)下面的問題,當要把一個服務器和一個架構結合起來時,卻發現他們不是被設計成協同工作的:
那么,怎么可以不修改服務器和架構代碼而確保可以在多個架構下運行web服務器呢?答案就是 Python Web Server Gateway Interface (或簡稱 WSGI,讀作“wizgy”)。
WSGI允許開發者將選擇web框架和web服務器分開。可以混合匹配web服務器和web框架,選擇一個適合的配對。
比如,可以在Gunicorn 或者 Nginx/uWSGI 或者 Waitress上運行 Django, Flask, 或 Pyramid。
真正的混合匹配,得益於WSGI同時支持服務器和架構:
web服務器必須具備WSGI接口,所有的現代Python Web框架都已具備WSGI接口,它讓你不對代碼作修改就能使服務器和特點的web框架協同工作。
WSGI由web服務器支持,而web框架允許你選擇適合自己的配對,但它同樣對於服務器和框架開發者提供便利使他們可以專注於自己偏愛的領域和專長而不至於相互牽制。
其他語言也有類似接口:java有Servlet API,Ruby 有 Rack。
2.3 定義WSGI接口
WSGI接口定義非常簡單,它只要求Web開發者實現一個函數,就可以響應HTTP請求。我們來看一個最簡單的Web版本的“Hello World!”:
def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return 'Hello World!'
上面的application()
函數就是符合WSGI標准的一個HTTP處理函數,它接收兩個參數:
- environ:一個包含所有HTTP請求信息的dict對象;
- start_response:一個發送HTTP響應的函數。
整個application()
函數本身沒有涉及到任何解析HTTP的部分,也就是說,把底層web服務器解析部分和應用程序邏輯部分進行了分離,這樣開發者就可以專心做一個領域了
不過,等等,這個application()
函數怎么調用?如果我們自己調用,兩個參數environ和start_response我們沒法提供,返回的str也沒法發給瀏覽器。
所以application()
函數必須由WSGI服務器來調用。有很多符合WSGI規范的服務器。而我們此時的web服務器項目的目的就是做一個既能解析靜態網頁還可以解析動態網頁的服務器
2.4 web服務器-----WSGI協議---->web框架 傳遞的字典
下面的信息,僅僅http傳遞給 web框架的部分信息,沒有必要全部寫清楚,只要知道這里有很多重要的信息即可,而這些信息在web框架中需要
{ 'HTTP_ACCEPT_LANGUAGE': 'zh-cn', 'wsgi.file_wrapper': <built-infunctionuwsgi_sendfile>, 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'uwsgi.version': b'2.0.15', 'REMOTE_ADDR': '172.16.7.1', 'wsgi.errors': <_io.TextIOWrappername=2mode='w'encoding='UTF-8'>, 'wsgi.version': (1,0), 'REMOTE_PORT': '40432', 'REQUEST_URI': '/', 'SERVER_PORT': '8000', 'wsgi.multithread': False, 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_HOST': '172.16.7.152: 8000', 'wsgi.run_once': False, 'wsgi.input': <uwsgi._Inputobjectat0x7f7faecdc9c0>, 'SERVER_PROTOCOL': 'HTTP/1.1', 'REQUEST_METHOD': 'GET', 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', 'HTTP_CONNECTION': 'keep-alive', 'uwsgi.node': b'ubuntu', 'HTTP_DNT': '1', 'UWSGI_ROUTER': 'http', 'SCRIPT_NAME': '', 'wsgi.multiprocess': False, 'QUERY_STRING': '', 'PATH_INFO': '/index.html', 'wsgi.url_scheme': 'http', 'HTTP_USER_AGENT': 'Mozilla/5.0(Macintosh;IntelMacOSX10_12_5)AppleWebKit/603.2.4(KHTML,likeGecko)Version/10.1.1Safari/603.2.4', 'SERVER_NAME': 'ubuntu' }
未完待續。。。
我的博客:https://www.cnblogs.com/dong4716138/
我的網站:http://howdoit.cn/