WSGI(Web Server Gateway Interface) Web 服務器網關接口。從名稱上來看WSGI就是一個網關,做用就是在協議之間進行轉換。具體而言,WSGI 是一個規範,它遵循這種規範將一個Web組件抽象成三個部件層:Web Server + Web Middleware + Web Application。除此以外,它還定義了 Web Server 如何與 Python 寫的 Web Application進行交互,使得 Python 寫的 Web Application 能夠和 Web Server 可以對接起來。如今通常會使用 Apache + wsgi_mod 的組合來實現Web Services。python
在 Web Services 處理方案中,有一個方案是目前應用最普遍的:
- 部署一個 Web Server(Apache) 專門用來處理 HTTP 協議層面相關的事情,EG. 如何在一個 HOST 上提供多個不一樣的虛擬主機:單IP多域名,單IP多端口等。nginx
那麼,Web Server 和 Application 之間就就須要解決交互的問題。而爲了解決這個問題,就定義 Web Server 和 Application 之間交互的規範。EG. Java 的 Servlet,Python 的 WSGI 等。定義這些規範的目的是爲了定義統一的標準,提高程序的可移植性。web
WSGI 至關於 Web Server 和 Python Application 之間的橋樑。其存在的目的有兩個:
1. 讓 Web Server 知道如何調用 Python Application,而且將 Client Request 傳遞給 Application。
2. 讓 Python Application 能理解 Client Request 並執行對應操做,以及將執行結果返回給 Web Server,最終響應到Client。segmentfault
當處理一個 WSGI 請求時,Server 爲 Application 提供 上下文信息 和一個 回調函數, Application 處理完請求以後,使用 Server 所提供的回調函數返回相對應請求的響應。瀏覽器
Server 首先會接收到User Request,而後根據規範調用 Application 並將預處理過的 Request 傳遞給 Application。由 Application 處理完 Request 以後將結果返回給 Web Server,最後 Web Server 將結果封裝成 HTTP Response 並響應給 User。 (重要的事情,已是第三遍了)服務器
每一個 Application 的入口都只有一個,就是說 Server 只能經過這一個入口調用 Application 並將 Client Request 傳遞給 Application。因此 Server 須要知道如何找到這一個 Application 的入口:架構
這是由一個 Python Module(通常由框架提供) 決定的,而且這個 Python Module 中須要包含由一個名稱爲 application 的可調用對象(該對象不管是 Function/Class 均可以)。而這一個可調用的 application 對象就是 Application 的惟一入口了。WSGI 定義了 application 對象的樣式:app
def application(environ, start_response): #該函數須要提供兩個形參
pass
EXAMPLE:假設 Application 的入口文件爲 /var/www/index.py
,那麼首先咱們須要在 Server 中配置好這一路徑(讓 Server 可以找到這個 Python Module),而後在 index.py 這個文件中寫入下面的 Application 入口實現代碼:框架
#使用 web.py 框架時的樣式
import web #由 web.py 框架提供了可調用對象 application() 做爲 Application 的入口
urls = (
'/.*', 'hello',
)
class hello(object):
def GET(self):
return "Hello, world."
app = web.application(urls, globals()).wsgifunc()
#Server 會根據配置找到這個文件,而後調用這個 application 對象
#由於 application 對象是惟一的入口,因此無論 Client Request 的路徑和數據是什麼, Server 都會調用這個對象來處理,具體的 Client Request 的處理過程交由 application 對象來完成,框架的使用者通常不須要關心這個對象內部是如何工做的,框架已經對其作了封裝。
Application 處理 Request 和 Response 都與 application 對象的兩個參數(environ、start_response)有關。svg
CGI 規範中要求的數據成員 :
REQUEST_METHOD: 請求方法,String類型,'GET', 'POST','PUT','DELETE'等
SCRIPT_NAME: HTTP請求的URL_Path中的用於查找到application對象的部分(EG. Web服務器能夠根據URL_Path的一部分來決定請求由哪一個虛擬主機來處理這個請求)
PATH_INFO: HTTP請求的URL_Path中剩餘的部分,也就是application對象要處理的部分
QUERY_STRING: HTTP請求中的查詢字符串,URL中'?'後面緊跟的內容
CONTENT_TYPE: HTTP headers頭部中的 content-type 內容
CONTENT_LENGTH:HTTP headers中的 content-length 內容
SERVER_NAME 和 SERVER_PORT: 服務器主機名和端口,這兩個值和前面的SCRIPT_NAME, PATH_INFO拼起來能夠獲得完整的URL路徑 EG. http://www.jmilkfan.com:80/virtual/private
SERVER_PROTOCOL: HTTP協議版本,HTTP/1.0或者HTTP/1.1
HTTP_: 和HTTP請求中的headers對應
WSGI 規範中要求的成員:
wsgi.version: 表示WSGI版本,一個元組(1, 0),表示版本1.0
wsgi.url_scheme: http或者https
wsgi.input: 一個類文件的輸入流,application能夠經過這個獲取HTTP request body
wsgi.errors: 一個輸出流,當 Application 出錯時,能夠將錯誤信息寫入這裏
wsgi.multithread: 當application對象可能被多個線程同時調用時,這個值須要爲True
wsgi.multiprocess: 當application對象可能被多個進程同時調用時,這個值須要爲True
wsgi.run_once: 當server指望application對象在進程的生命週期內只被調用一次時,該值爲True
start_resposne :start_resposne的引用指向一個回調函數(在 Server 中定義),這個回調函數會接受兩個必選參數(status,resposne_headers)和一個可選參數(exc_info)。EG. start_resposne(status,resposne_headers,exc_info=None)
當 application 對象根據 environ 參數的 Info 執行完 Client Request 的業務邏輯以後,須要返回結果給 Server 。並且 HTTP Response 須要包含 status、headers、body 等元素,因此在 application 對象將 body 做爲返回值 return 以前,須要先調用 start_response()將 status、headers 先返回給 Server,同時也是告訴Server,application 對象要開始返回 body 了。當Web Server 接受完這些元素以後,就能夠將這些元素封裝成爲 HTTP Response 響應給 Client。
(header_name, header_value)
做爲元素的列表類型對象,分別表示HTTP響應的 headers 及其內容。回調函數:就是一個經過函數指針(變量的引用)調用的函數。若是你把函數的指針(引用)做爲參數傳遞給另外一個函數,當這個指針(引用)被用來調用其所指向的函數時,咱們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。因此 application 對象會在執行完請求的操做以後纔會使用參數 start_response ,回調該變量指向的函數,以此來將 status、headers return 給 Server 。
body = []
status_headers == [None,None]
def status_response(status,headers):
status_headers[:] = [status,headers]
return body.append(status_headers)
application對象的返回值 body 用於 HTTP 響應,若是沒有 body 返回,那麼能夠返回 None。若是有 body 返回,那麼要求返回 body 必須是一個可迭代的對象。Server 經過遍歷這個可迭代對象能夠得到 body 的所有內容。
EXAMPLE:
def application(environ, start_response): #
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers) #將 body == ['hello, world'] 做爲返回值 return 以前,先調用 start_response(status, response_headers) 將 status、headers 先返回給 Server
return ['hello, world']
Server 經過配置和 Python Module 來找到 Application 的入口,在找到 application 對象以後,Server 會經過將 Client Request 全部的 Info 和一些符合規範的參數信息傳遞給 application 對象做爲實參,以此來實現 Server 將客戶端請求傳遞給 Application。而後 application 對象執行業務邏輯,在返回 body 以前須要調用start_resposne()回調函數將HTTP響應所須要的信息返回。最後返回一個可迭代的對象 body ,Server 最後經過遍從來獲取完整的 Body 數據。
注意:environ 和 start_response() 是須要在Server中的生成和定義的。
WSGI Middleware 也是 WSGI 規範的一部分。 Middleware 是一個運行在 Server 和 Application 之間的應用。它同時具有了 Server 和 Application 的角色功能,對於 Server 來講,它是一個 Application;對於 Application來講,它是一個 Server。*middleware並不修改 Server 端和 Application 端的規範,只是同時實現了這兩個角色的功能而已,所以它能夠在兩端之間起協調做用。並且 Middleware 能夠將 Cllient HTTP Request 路由給不一樣的 Application 。*
Middleware 是如何工做的:
1.Server 收到客戶端的 HTTP 請求後,生成了environ_s
,而且已經定義了start_response_s
。
2.Server 調用 Middleware 的 application 對象,傳遞的參數是environ_s
和start_response_s
。
3.Middleware 會根據 environ 執行業務邏輯,生成environ_m
,而且已經定義了start_response_m
。
4.Middleware 再調用 Application 的 application 對象,傳遞參數是environ_m
和start_response_m
。Application 的 application 對象處理完成後,會調用 start_response_m
而且返回結果給 Middleware,存放在 result_m
中。
5.Middleware 處理 result_m
,而後生成 result_s
,接着調用 start_response_s
,並返回結果 result_s
給 Server 端。Server 端獲取到 result_s
後就能夠發送結果給客戶端了。
從上面的流程能夠看出middleware應用的幾個特色:
1. Server認爲middleware是一個application。
2. Application認爲middleware是一個server。
3. Middleware能夠有多層。
咱們能夠將 WSGI Middleware 了理解爲 Server 和 Application 交互的一層包裝,通過不一樣的 Middleware ,便擁有了不一樣的功能,EG. URL 路由轉發、權限認證。由於Middleware能過處理全部經過的 request 和 response,因此要作什麼均可以,沒有限制。好比能夠檢查 request 是否有非法內容,檢查 response 是否有非法內容,爲 request 加上特定的 HTTP header 等。這些不一樣的 Middleware 組合便造成了 WSGI 的框架,好比咱們將要介紹的 Paste。
要使用WSGI,須要分別實現 Server 角色和 Application 角色。
Application 端通常是由Python的各類框架(Django, web.py)來實現的,通常開發者不須要關心 WSGI 的實現,框架會提供接口讓開發者獲取 HTTP 請求的內容以及發送 HTTP 響應。
Server 端的實現會比較複雜一點,這個主要是由於軟件架構的緣由。通常經常使用的Web服務器,如Apache和nginx,都不會內置WSGI的支持,而是經過擴展插件來完成。EG. Apache + mod_wsgi
來支持WSGI。 Apache 和 mod_wsgi 之間經過程序內部接口傳遞信息,mod_wsgi 會實現 WSGI 的 Server端、進程管理以及對 application 的調用。Nginx + uWSGI
,用 nginx 的協議將請求封裝好,發送給應用服務器,應用服務器會實現 WSGI 的 Server 端、進程管理以及對 application 的調用。
WSGI 簡介 《Openstack 設計與實現》