WSGI Python Web Server Gateway Interface 規范學習
由于Python的靈活性,提供了多種方式可以作為服務端語言,包括Python編寫的服務器(Medusa)、Python處理模塊(mod_python),或者使用CGI、FastCGI方式觸發Python腳本。 為了能夠編寫更通用的Web端程序,提出了WSGI接口作為標準接口規范,類似于Java中的Serverlet,一旦編寫完成后,可以運行在不同的App框架中。
WSGI接口涉及兩個方面:一面是:服務器(server)或網關(gateway),相對別一面是:應用程序(application)或框架(framework)。服務端運行由應用程或框架提供的可執行的對像實例,至于這個可執行對象的是如果獲得的細節,不在WSGI規范定義之內,而是同server或gataway去處理。
Application/Framework 端
Application端是一個callable term,可以是function、class、method等,接收兩個參數environ、start_response。當application被server調用時,必須返回一個iterable的bytestrings或者是zero(可以使用yield返回一個生成器)。
WSGI 是為框架或服務器開發人員提供的工具,而不是為應用人員提供的。
When called by the server, the application object must return an iterable yielding zero or more byte strings.
服務器調用時,應當以無緩存的形式將產生的內容發送給客戶端。
方法:len()、close()
Server/Gateway 端
中間件 Middleware 扮演兩個角色
Middleware常扮演以下角色:
- 根據目標URL將請求路由到不同的Application進行處理
- 允許多個Application或Framework運行在相同的進程中
- 通過網絡內的請求轉發實現負載均衡和遠程處理
- 實現內容的后續處理,例如XSL樣式表
中間件的存在對于服務端和應用端應該都是透明的。
environ 變量
environ 是一個字典變量。
變量名 | 備注 |
---|---|
REQUEST_METHOD | HTTP請求方法,GET、POST、PUT,不能為空 |
SCRIPT_NAME | 腳本名稱,可以為空 |
PATH_INFO | 請求URL中的一部分,可以為空 |
QUERY_STRING | 請求URL中問號(?)之后的部分,可以為空 |
CONTENT_TYPE | 請求中的Content_Type字段,可以為空 |
CONTENT_LENGTH | 請求中的Content_Length,可以為空 |
SERVER_NAME , SERVER_PORT | 不能為空 |
SERVER_PROTOCOL | 客戶端發送請求采用的協議及版本 |
HTTP_ 變量 | 客戶端請求頭中的參數,可以為空 |
CGI方式需要提供的參數略有不同,具體可以參考PEP3333
A WSGI-compliant server or gateway should document what variables it provides, along with their definitions as appropriate. Applications should check for the presence of any variables they require, and have a fallback plan in the event such a variable is absent.
Input、Error流
服務器端必須支持以下幾個方法
方法 | 流 |
---|---|
read(size) | Input |
readline() | Input |
readlines(hint) | Input |
iter() | Input |
flush() | errors |
write(str) | errors |
writelines(seq) | errors |
start_response()
方法示例start_response(status, response_headers, exec_info = None)
。
start_response 接收兩個參數start_response(status, response_headers)
,status是狀態返回信息,諸如“200 OK”或者“404 Not Found”,純文本,不能包含任何控制符號。response_headers是一個形如(header_name, header_value)的tuples,必須是Python的List。header_name必須是RFC2616中定義的名稱,header_value不包含結束符號及任何控制符號,包括換行等。
一般來說,服務器端負責確保發送的header的正確性,如果應用忽略了某個http頭參數,那么服務器應該給補充進去。
服務端應該檢查是否向客戶端發送了保持鏈接的頭參數,如果發現,應該拋出錯誤。
Content-Length 頭的處理
如果應用端提供了 Content-Length 請求頭,服務端不應當傳遞超過這個長度的內容。處理方式是停止發送內容,或產生一個報錯。如果沒有提供足夠的內容,則應正常關閉鏈接不產生錯誤。
如果沒有提供 Content-Length 頭,則服務端可以自己決定采用哪種處理方式,最簡單的就是響應結束后關閉鏈接。某些情況下,服務端可以自己產生 Content-Length , 或者盡量避免關閉鏈接。如果服務端和客戶端都支持 HTTP/1.1 分塊編碼,則服務端需要為每個塊提供一個 Content-Length。
緩存和流處理 Buffering and Streaming
write() callable
一些編程框架提供了緩存的 write() 函數以及一個 flush() 函數,用于刷新緩存,但是很遺憾標準的WSGI無法實現這個需求。但WSGI仍提供了一個特殊 write() 函數,來實現這些迫切的需求。
write() 由 start_response 返回,接收一個參數。一個應用必須返回一個 iterable 對象。
錯誤處理