根據WSGI協議本身實現mini-web框架(1)

1. 爲何要研究WSGI

我以前在學習web開發時,每每都是根據MVT等架構直接寫所謂的「視圖」,使用其自己自帶的http服務器,當時就一直很好奇,爲何有了HTTP協議以後,還要研究WSGI協議,它到底有什麼用?html

因爲「工做要緊」因此不少細枝末節的事情 都被安排到推遲,最終遲遲沒有研究java

後來有個空閒時間的機會,終於能夠靜下來研究WSGInode

 

2. 說說WSGI與HTTP服務器之間的調用過程

2.1 瀏覽器請求動態頁面過程

 

看完上圖估計也就知道了所謂的WSGI到底有什麼用,若是仍是不明白,那我就通俗點說:python

web服務器接收到瀏覽器發送過來的請求以後,須要將瀏覽器傳遞過來的不少數據(例如user-agent、cookie等)都要告訴你的「視圖」,由於只有「視圖」接收到數據,纔可以進一步處理,例如判斷是否登陸等web

因此這就須要web服務器與「視圖」之間的傳遞,此時WSGI就是起到傳遞的做用,只不過這個傳遞的過程有些複雜 能夠參考上圖二、三、四、6步驟ubuntu

 

2.2 用個例子來講明WSGI

怎麼在你剛創建的Web服務器上運行一個Django應用Flask應用,如何不作任何改變而適應不一樣的web架構呢?瀏覽器

在之前,選擇 Python web 架構會受制於可用的web服務器,反之亦然。若是架構和服務器能夠協同工做,那就行了:服務器

但有可能面對(或者曾有過)下面的問題,當要把一個服務器和一個架構結合起來時,卻發現他們不是被設計成協同工做的:cookie

那麼,怎麼能夠不修改服務器和架構代碼而確保能夠在多個架構下運行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!'
上面的函數就是符合WSGI標準的一個HTTP處理函數,它接收兩個參數:
application()
  • 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/

相關文章
相關標籤/搜索