Python Web開發中,WSGI協議的作用和實現原理詳解
首先理解下面三個概念:
WSGI:全稱是Web Server Gateway Interface,WSGI不是伺服器,python模組,框架,API或者任何軟體,只是一種規範,描述web server如何與web application通訊的規範。
uwsgi:與WSGI一樣是一種協議,是uWSGI伺服器的獨佔協議,用於定義傳輸資訊的型別(type of information),每一個uwsgi packet前4byte為傳輸資訊型別的描述,與WSGI協議是兩種東西,據說該協議是fcgi協議的10倍快。
uWSGI:是一個web伺服器,實現了WSGI協議、uwsgi協議、http協議等。
WSGI協議主要包括server和application兩部分:
其中application部分:
示例程式碼:
def application(environ, start_response): status = '200 OK' response_headers = [('Content-Type', 'text/html')] # application內部呼叫start_response start_response(status, response_headers) # 解析environ資訊,業務邏輯處理後,返回對應的響應資訊(下面程式碼只是模擬業務處理)file_name = environ['PATH_INFO'] if file_name == "/index.py": return index(file_name) elif file_name == "/center.py": return center(file_name) else: return 'Hello world a simple WSGI application!'
有了WSGI,我們在框架中只關心如何從environ這個dict(wgsi規定傳過來一個字典)物件拿到HTTP請求資訊,然後構造HTML,通過start_response()傳送Header,最後返回Body。
整個application()函式本身沒有涉及到任何解析HTTP的部分。 也就是說,底層程式碼不需要我們自己編寫,我們只負責業務邏輯部分即可。
但是我們想一下,這個application()函式怎麼呼叫?如果我們自己呼叫,兩個引數environ和start_response我們沒法提供,返回的str也沒法發給瀏覽器。
擷取server端部分程式碼例項如下:
# 重點關注邏輯 # 準備一個字典,裡面存放需要傳遞給web框架的資料 env = dict() # ----------更新--------- env['PATH_INFO'] = file_name # 例如 index.py(模擬請求資訊) # 重點關注邏輯 # 伺服器呼叫框架中實現的application函式,並將包含請求資訊的字典和獲取響應頭的函式傳入 response_body = self.application(env, self.start_response) # 合併header和body(響應客戶端的請求,這個邏輯不用關注) response_header = "HTTP/1.1 {status}\r\n".format(status=self.headers[0]) response_header += "Content-Type: text/html; charset=utf-8\r\n" response_header += "Content-Length: %d\r\n" % len(response_body.encode("utf-8")) for temp_head in self.headers[1]: response_header += "{0}:{1}\r\n".format(*temp_head) response = response_header + "\r\n" response += response_body client_socket.send(response.encode('utf-8')) # 重點關注邏輯 # server端實現了start_response函式的定義 def start_response(self, status, headers): """這個方法,會在 web框架中被預設呼叫""" response_header_default = [ ("Data", time.time()), ("Server", "ItCast-python mini web server") ] # 將狀態碼/相應頭資訊儲存起來 # [字串, [xxxxx, xxx2]] self.headers = [status, response_header_default + headers]
這段程式碼,是在客戶端請求動態資源時啟動,即伺服器需要向後端框架請求資源。程式碼解析已在程式碼中註釋。
所以我們基本可以獲得如下結論:
要實現WSGI協議,必須同時實現web server端和web application端
當前執行在WSGI協議之上的web框架有Torando,Flask,Django等
比較常用的WSGI協議伺服器有:uWSGI,gunicorn等
1、框架需要實現WSGI協議,例如:Flask,Django等
2、environ 和 start_response 由 http server 提供並實現 3、environ 變數是包含了請求資訊的字典 4、Application 內部在返回前呼叫 start_response 5、application()函式必須由WSGI伺服器來呼叫
server要履行的任務:
1、接收HTTP請求
2、解析HTTP請求
3、準備 environ請求引數
4、定義 start_response 函式
5、組裝響應頭和相應體返回給客戶端
application要履行的責任:
1、解析伺服器發來的請求資訊
2、根據請求資訊,進行業務處理
3、返回所需要的資料
至此,您應該對WSGI有了一定的瞭解吧。
擴充套件閱讀:
目前一些主要的實現了WSGI協議的伺服器:
gunicorn
Gunicorn(從Ruby下面的Unicorn發展而來):依賴Nginx的代理行為,同Nginx進行功能上的分離。由於不需要直接處理使用者來的請求(都被Nginx先處理),Gunicorn不需要完成相關的功能,其內部邏輯非常簡單:接受從Nginx來的動態請求,處理完之後返回給Nginx,由後者返回給使用者。
由於功能定位很明確,Gunicorn得以用純Python開發:大大縮短了開發時間的同時,效能上也不會很掉鏈子。同時,它也可以配合Nginx的代理之外的別的Proxy模組工作,其配置也相應比較簡單。
配置上的簡單,大概是它流行的最大的原因。
uwsgi
因為使用C語言開發,會和底層接觸的更好,配置也是比較方便,目前和gunicorn兩個算是部署時的唯二之選。
以下是通常的配置檔案
fcgi
不多說,用的少。
bjoern