WSGI 詳解 和中間件的一些內容


WSGI 簡介

 

wsgi代碼源碼詳解>>點我

 

介紹

 

要很好地理解下面的代碼,最好有一定的 socket 編程基礎,了解 socket 的基本概念和流程。

 

wsgiref 是 PEP 333 定義的 wsgi 規范的范例實現,里面的功能包括了:

 

  • 操作 wsgi 的環境變量
  • 應答頭部的處理
  • 實現簡單的 HTTP server
  • 簡單的對程序端和服務器端校驗函數

 

我們先看一個簡單的代碼實例,然后跟着例子去理解源碼:

 

app.py

 

 

server.py

 

 

然后執行 python server.py 啟動 sever,用 curl 發送一個請求 curl -i http://localhost:8000/,會有以下輸出:

 

 

server 的終端會有一條記錄:

 

 

如何使用就講到這里,下面就開始源碼之旅吧!

 

源碼分析

 

你可以使用 python -c 'import wsgiref; help(wsgiref)' 查看 wsgiref 庫的路徑和簡介等信息,wsgiref 文件夾的結構如下:

 

 

主要的代碼結構如下圖所示:

 

 

simple_server.py

 

我們先看一下 make_server 是怎么啟動一個 wsgi 服務器的:

 

 

這個函數做的事情就是:監聽在本地的端口上,接受來自客戶端的請求,通過 WSGIServer 和 WSGIRequestHandler 處理后,把請求交給程序的的可調用對象 app,然后返回 app 的結果給客戶端。

 

這里有兩個重要的類:WSGIServer 和 WSGIRequestHandler。下面分別看一下它們的代碼和執行的功能。

 

 

WSGIServer 在原來的 HTTPServer 上面封裝了一層,在原來的 HTTPServer 的基礎上又額外做了下面的事情:

 

  • 覆寫原來的 server_bind 函數,添加初始化 environ 變量的動作
  • 添加了處理滿足 wsgi 的 app 函數:set_app 和 get_app

 

然后看另外一個類 WSGIRequestHandler:

 

 

這個類從名字就能知道它的功能——處理客戶端的 HTTP 請求,它也是在原來處理 http 請求的BaseHTTPRequestHandler 類上添加了 wsgi 規范相關的內容。

 

  • get_environ: 解析 environ 變量
  • handle: 處理請求,把封裝的環境變量交給 ServerHandler,然后由 ServerHandler 調用 wsgi app,ServerHandler 類會在下面介紹。

 

handler.py

 

這個文件主要是 wsgi server 的處理過程,定義 start_response、調用 wsgi app 、處理 content-length 等等。

 

可以參考這篇文章里的 wsgi server 的簡單實現。

 

 

一條 HTTP 請求的旅程

 

服務器端啟動服務,等到客戶端輸入 curl -i http://localhost:8000/ 命令,摁下回車鍵,看到終端上的輸出,整個過程中,wsgi 的服務器端發生了什么呢?

 

  1. 服務器程序創建 socket,並監聽在特定的端口,等待客戶端的連接
  2. 客戶端發送 http 請求
  3. socket server 讀取請求的數據,交給 http server
  4. http server 根據 http 的規范解析請求,然后把請求交給 WSGIServer
  5. WSGIServer 把客戶端的信息存放在 environ 變量里,然后交給綁定的 handler 處理請求
  6. HTTPHandler 解析請求,把 method、path 等放在 environ,然后 WSGIRequestHandler 把服務器端的信息也放到 environ 里
  7. WSGIRequestHandler 調用綁定的 wsgi ServerHandler,把上面包含了服務器信息,客戶端信息,本次請求信息得 environ 傳遞過去
  8. wsgi ServerHandler 調用注冊的 wsgi app,把 environ 和 start_response 傳遞過去
  9. wsgi app 將reponse header、status、body 回傳給 wsgi handler
  10. 然后 handler 逐層傳遞,最后把這些信息通過 socket 發送到客戶端
  11. 客戶端的程序接到應答,解析應答,並把結果打印出來。

 

 

背景

Python Web 開發中,服務端程序可以分為兩個部分,一是服務器程序,二是應用程序前者負責把客戶端請求接收,整理,后者負責具體的邏輯處理為了方便應用程序的開發,我們把常用的功能封裝起來,成為各種Web開發框架,例如 Django, Flask, Tornado。不同的框架有不同的開發方式,但是無論如何,開發出的應用程序都要和服務器程序配合,才能為用戶提供服務。這樣,服務器程序就需要為不同的框架提供不同的支持。這樣混亂的局面無論對於服務器還是框架,都是不好的。對服務器來說,需要支持各種不同框架,對框架來說,只有支持它的服務器才能被開發出的應用使用。

這時候,標准化就變得尤為重要。我們可以設立一個標准,只要服務器程序支持這個標准,框架也支持這個標准,那么他們就可以配合使用。一旦標准確定,雙方各自實現。這樣,服務器可以支持更多支持標准的框架,框架也可以使用更多支持標准的服務器

Python Web開發中,這個標准就是 The Web Server Gateway Interface, 即 WSGI. 這個標准在PEP 333中描述,后來,為了支持 Python 3.x, 並且修正一些問題,新的版本在PEP 3333中描述。

WSGI 是什么

WSGI 是服務器程序與應用程序的一個約定,它規定了雙方各自需要實現什么接口,提供什么功能,以便二者能夠配合使用

WSGI 不能規定的太復雜,否則對已有的服務器來說,實現起來會困難,不利於WSGI的普及。同時WSGI也不能規定的太多,例如cookie處理就沒有在WSGI中規定,這是為了給框架最大的靈活性。要知道WSGI最終的目的是為了方便服務器與應用程序配合使用,而不是成為一個Web框架的標准。

另一方面,WSGI需要使得middleware(是中間件么?)易於實現。middleware處於服務器程序與應用程序之間,對服務器程序來說,它相當於應用程序,對應用程序來說,它相當於服務器程序。這樣,對用戶請求的處理,可以變成多個 middleware 疊加在一起,每個middleware實現不同的功能。請求從服務器來的時候,依次通過middleware,響應從應用程序返回的時候,反向通過層層middleware。我們可以方便地添加,替換middleware,以便對用戶請求作出不同的處理。

WSGI 內容概要

WSGI主要是對應用程序與服務器端的一些規定,所以,它的主要內容就分為兩個部分。

應用程序

WSGI規定:

1. 應用程序需要是一個可調用的對象 

在Python中:

  • 可以是函數
  • 可以是一個實例,它的類實現了__call__方法
  • 可以是一個類,這時候,用這個類生成實例的過程就相當於調用這個類

同時,WSGI規定:

2. 可調用對象接收兩個參數 

這樣,如果這個對象是函數的話,它看起來要是這個樣子:

# callable function
def application(environ, start_response):
    pass

如果這個對象是一個類的話,它看起來是這個樣子:

# callable class
class Application:
    def __init__(self, environ, start_response):
        pass

如果這個對象是一個類的實例,那么,這個類看起來是這個樣子:

# callable object
class ApplicationObj:
    def __call__(self, environ, start_response):
        pass

最后,WSGI還規定:

3.可調用對象要返回一個值,這個值是可迭代的。 

 

middleware

另外,有些功能可能介於服務器程序和應用程序之間,例如,服務器拿到了客戶端請求的URL, 不同的URL需要交由不同的函數處理,這個功能叫做 URL Routing,這個功能就可以放在二者中間實現,這個中間層就是 middleware。

middleware對服務器程序和應用是透明的,也就是說,服務器程序以為它就是應用程序,而應用程序以為它就是服務器。這就告訴我們,middleware需要把自己偽裝成一個服務器,接受應用程序,調用它,同時middleware還需要把自己偽裝成一個應用程序,傳給服務器程序。

其實無論是服務器程序,middleware 還是應用程序,都在服務端,為客戶端提供服務,之所以把他們抽象成不同層,就是為了控制復雜度,使得每一次都不太復雜,各司其職。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM