wsgiref 原始碼解析

發表於2017-02-21

圖片來源

介紹

要很好地理解下面的程式碼,最好有一定的 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/ 命令,摁下Enter鍵,看到終端上的輸出,整個過程中,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. 客戶端的程式接到應答,解析應答,並把結果列印出來。

comments powered by Disqus

相關文章