wsgiref — WSGI 工具和參考實現

原始碼: Lib/wsgiref


Web 伺服器閘道器介面(WSGI)是 Web 伺服器軟體和用 Python 編寫的 Web 應用程式之間的標準介面。擁有標準介面使得將支援 WSGI 的應用程式與許多不同的 Web 伺服器一起使用變得容易。

只有 Web 伺服器和程式設計框架的作者才需要了解 WSGI 設計的每個細節和邊緣情況。您不需要了解 WSGI 的每個細節,即可安裝 WSGI 應用程式或使用現有框架編寫 Web 應用程式。

wsgiref 是 WSGI 規範的參考實現,可用於向 Web 伺服器或框架新增 WSGI 支援。它提供了用於操作 WSGI 環境變數和響應頭的實用程式、用於實現 WSGI 伺服器的基類、一個服務 WSGI 應用程式的演示 HTTP 伺服器、用於靜態型別檢查的型別,以及一個驗證工具,用於檢查 WSGI 伺服器和應用程式是否符合 WSGI 規範 (PEP 3333)。

有關 WSGI 的更多資訊以及教程和其他資源的連結,請參見 wsgi.readthedocs.io

wsgiref.util – WSGI 環境實用程式

此模組提供了各種用於處理 WSGI 環境的實用函式。WSGI 環境是一個字典,其中包含 PEP 3333 中描述的 HTTP 請求變數。所有接受 environ 引數的函式都期望提供一個符合 WSGI 的字典;請參閱 PEP 3333 以獲取詳細規範,並參閱 WSGIEnvironment 以獲取可在型別註解中使用的類型別名。

wsgiref.util.guess_scheme(environ)

透過檢查 environ 字典中是否存在 HTTPS 環境變數,返回 wsgi.url_scheme 應該是“http”還是“https”的猜測。返回值是一個字串。

此函式在建立封裝 CGI 或類 CGI 協議(如 FastCGI)的閘道器時很有用。通常,提供此類協議的伺服器在透過 SSL 接收請求時會包含一個 HTTPS 變數,其值為“1”、“yes”或“on”。因此,如果找到此類值,此函式返回“https”,否則返回“http”。

wsgiref.util.request_uri(environ, include_query=True)

使用 PEP 3333 的“URL 重建”部分中的演算法,返回完整的請求 URI,可選地包括查詢字串。如果 include_query 為 false,則查詢字串不包含在生成的 URI 中。

wsgiref.util.application_uri(environ)

類似於 request_uri(),但 PATH_INFOQUERY_STRING 變數被忽略。結果是請求所指向的應用程式物件的基 URI。

wsgiref.util.shift_path_info(environ)

PATH_INFO 中的單個名稱移動到 SCRIPT_NAME 並返回該名稱。environ 字典會被 就地修改;如果您需要保持原始的 PATH_INFOSCRIPT_NAME 不變,請使用副本。

如果 PATH_INFO 中沒有剩餘的路徑段,則返回 None

通常,此例程用於處理請求 URI 路徑的每個部分,例如將路徑視為一系列字典鍵。此例程修改傳入的環境,使其適合呼叫位於目標 URI 的另一個 WSGI 應用程式。例如,如果 WSGI 應用程式位於 /foo,並且請求 URI 路徑是 /foo/bar/baz,並且位於 /foo 的 WSGI 應用程式呼叫 shift_path_info(),它將收到字串“bar”,並且環境將更新以適合傳遞給位於 /foo/bar 的 WSGI 應用程式。也就是說,SCRIPT_NAME 將從 /foo 更改為 /foo/bar,而 PATH_INFO 將從 /bar/baz 更改為 /baz

PATH_INFO 只是一個“/”時,此例程返回一個空字串,並在 SCRIPT_NAME 末尾新增一個斜槓,即使通常會忽略空路徑段,並且 SCRIPT_NAME 通常不會以斜槓結尾。這是有意為之的行為,以確保應用程式在使用此例程進行物件遍歷時,能夠區分以 /x 結尾的 URI 和以 /x/ 結尾的 URI。

wsgiref.util.setup_testing_defaults(environ)

為測試目的更新 environ 中的簡單預設值。

此例程添加了 WSGI 所需的各種引數,包括 HTTP_HOSTSERVER_NAMESERVER_PORTREQUEST_METHODSCRIPT_NAMEPATH_INFO 和所有 PEP 3333 定義的 wsgi.* 變數。它只提供預設值,不替換這些變數的任何現有設定。

此例程旨在使 WSGI 伺服器和應用程式的單元測試更容易設定虛擬環境。實際的 WSGI 伺服器或應用程式不應使用它,因為資料是假的!

用法示例(另請參閱 demo_app() 以獲取另一個示例)

from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server

# A relatively simple WSGI application. It's going to print out the
# environment dictionary after being updated by setup_testing_defaults
def simple_app(environ, start_response):
    setup_testing_defaults(environ)

    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]

    start_response(status, headers)

    ret = [("%s: %s\n" % (key, value)).encode("utf-8")
           for key, value in environ.items()]
    return ret

with make_server('', 8000, simple_app) as httpd:
    print("Serving on port 8000...")
    httpd.serve_forever()

除了上面的環境函式,wsgiref.util 模組還提供了這些雜項實用程式

wsgiref.util.is_hop_by_hop(header_name)

如果“header_name”是 HTTP/1.1 “逐跳”頭,則返回 True,如 RFC 2616 所定義。

class wsgiref.util.FileWrapper(filelike, blksize=8192)

wsgiref.types.FileWrapper 協議的具體實現,用於將檔案類物件轉換為迭代器。生成的物件是可迭代物件。當物件被迭代時,可選的 blksize 引數將重複傳遞給 filelike 物件的 read() 方法以獲取要生成(yield)的位元組串。當 read() 返回空位元組串時,迭代結束且不可恢復。

如果 filelike 具有 close() 方法,則返回的物件也將具有 close() 方法,並且在呼叫時,它將呼叫 filelike 物件的 close() 方法。

用法示例:

from io import StringIO
from wsgiref.util import FileWrapper

# We're using a StringIO-buffer for as the file-like object
filelike = StringIO("This is an example file-like object"*10)
wrapper = FileWrapper(filelike, blksize=5)

for chunk in wrapper:
    print(chunk)

3.11 版本發生變化: 已移除對 __getitem__() 方法的支援。

wsgiref.headers – WSGI 響應頭工具

此模組提供了一個單一類 Headers,用於使用類似對映的介面方便地操作 WSGI 響應頭。

class wsgiref.headers.Headers([headers])

建立一個類似對映的物件,封裝 headersheaders 必須是 PEP 3333 中描述的頭名稱/值元組列表。headers 的預設值是一個空列表。

Headers 物件支援典型的對映操作,包括 __getitem__(), get(), __setitem__(), setdefault(), __delitem__()__contains__()。對於這些方法中的每一個,鍵是頭名稱(不區分大小寫),值是與該頭名稱關聯的第一個值。設定頭會刪除該頭的任何現有值,然後在封裝的頭列表末尾新增一個新值。頭部的現有順序通常保持不變,新頭部新增到封裝列表的末尾。

與字典不同,當您嘗試獲取或刪除封裝頭列表中不存在的鍵時,Headers 物件不會引發錯誤。獲取不存在的頭只返回 None,刪除不存在的頭則不執行任何操作。

Headers 物件也支援 keys()values()items() 方法。如果存在多值頭,keys()items() 返回的列表可能包含多次相同的鍵。Headers 物件的 len() 與其 items() 的長度相同,也與封裝的頭列表的長度相同。事實上,items() 方法只返回封裝的頭列表的副本。

Headers 物件呼叫 bytes() 會返回一個格式化的位元組串,適合作為 HTTP 響應頭傳輸。每個頭都與其值放在一行,用冒號和空格分隔。每行以回車符和換行符結尾,位元組串以空行結尾。

除了其對映介面和格式化功能外,Headers 物件還具有以下方法,用於查詢和新增多值頭,以及新增帶有 MIME 引數的頭

get_all(name)

返回指定名稱頭的所有值的列表。

返回的列表將按照它們在原始頭列表中出現的順序或新增到此例項的順序進行排序,並且可能包含重複項。任何已刪除並重新插入的欄位始終會附加到頭列表。如果不存在具有給定名稱的欄位,則返回一個空列表。

add_header(name, value, **_params)

新增一個(可能多值的)頭部,可選的 MIME 引數透過關鍵字引數指定。

name 是要新增的頭欄位。關鍵字引數可用於設定頭欄位的 MIME 引數。每個引數必須是字串或 None。引數名稱中的下劃線會被轉換為破折號,因為破折號在 Python 識別符號中是非法的,但許多 MIME 引數名稱包含破折號。如果引數值是字串,它將以 name="value" 的形式新增到頭值引數中。如果它是 None,則只新增引數名稱。(這用於沒有值的 MIME 引數。)用法示例

h.add_header('content-disposition', 'attachment', filename='bud.gif')

以上將新增一個看起來像這樣的頭部

Content-Disposition: attachment; filename="bud.gif"

3.5 版本發生變化: headers 引數是可選的。

wsgiref.simple_server – 一個簡單的 WSGI HTTP 伺服器

此模組實現了一個簡單的 HTTP 伺服器(基於 http.server),用於服務 WSGI 應用程式。每個伺服器例項在給定的主機和埠上服務一個 WSGI 應用程式。如果您希望在單個主機和埠上服務多個應用程式,您應該建立一個 WSGI 應用程式,該應用程式解析 PATH_INFO 以選擇為每個請求呼叫哪個應用程式。(例如,使用 wsgiref.util 中的 shift_path_info() 函式。)

wsgiref.simple_server.make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler)

建立一個新的 WSGI 伺服器,監聽 hostport,接受 app 的連線。返回值是提供的 server_class 的一個例項,並將使用指定的 handler_class 處理請求。app 必須是一個 WSGI 應用程式物件,如 PEP 3333 所定義。

用法示例:

from wsgiref.simple_server import make_server, demo_app

with make_server('', 8000, demo_app) as httpd:
    print("Serving HTTP on port 8000...")

    # Respond to requests until process is killed
    httpd.serve_forever()

    # Alternative: serve one request, then exit
    httpd.handle_request()
wsgiref.simple_server.demo_app(environ, start_response)

此函式是一個小而完整的 WSGI 應用程式,它返回一個包含“Hello world!”訊息和 environ 引數中提供的鍵/值對列表的文字頁面。它對於驗證 WSGI 伺服器(例如 wsgiref.simple_server)是否能夠正確執行簡單的 WSGI 應用程式非常有用。

可呼叫物件 start_response 應該遵循 StartResponse 協議。

class wsgiref.simple_server.WSGIServer(server_address, RequestHandlerClass)

建立 WSGIServer 例項。server_address 應該是一個 (host,port) 元組,而 RequestHandlerClass 應該是 http.server.BaseHTTPRequestHandler 的子類,用於處理請求。

您通常不需要呼叫此建構函式,因為 make_server() 函式可以為您處理所有細節。

WSGIServerhttp.server.HTTPServer 的子類,因此其所有方法(例如 serve_forever()handle_request())都可用。WSGIServer 還提供了這些 WSGI 特有的方法

set_app(application)

將可呼叫物件 application 設定為將接收請求的 WSGI 應用程式。

get_app()

返回當前設定的應用程式可呼叫物件。

然而,通常您不需要使用這些額外的方法,因為 set_app() 通常由 make_server() 呼叫,而 get_app() 主要用於請求處理程式例項。

class wsgiref.simple_server.WSGIRequestHandler(request, client_address, server)

為給定 request (即 socket)、client_address (一個 (host,port) 元組) 和 server (WSGIServer 例項) 建立一個 HTTP 處理器。

您不需要直接建立此類的例項;它們由 WSGIServer 物件在需要時自動建立。但是,您可以對此類進行子類化,並將其作為 handler_class 提供給 make_server() 函式。子類中可能需要覆蓋的一些相關方法

get_environ()

返回請求的 WSGIEnvironment 字典。預設實現複製 WSGIServer 物件的 base_environ 字典屬性的內容,然後新增從 HTTP 請求派生的各種標頭。每次呼叫此方法都應返回一個新字典,其中包含 PEP 3333 中指定的所有相關 CGI 環境變數。

get_stderr()

返回應該用作 wsgi.errors 流的物件。預設實現只是返回 sys.stderr

handle()

處理 HTTP 請求。預設實現使用 wsgiref.handlers 類建立處理程式例項,以實現實際的 WSGI 應用程式介面。

wsgiref.validate — WSGI 一致性檢查器

在建立新的 WSGI 應用程式物件、框架、伺服器或中介軟體時,使用 wsgiref.validate 驗證新程式碼的一致性可能會很有用。此模組提供了一個函式,該函式建立 WSGI 應用程式物件,這些物件驗證 WSGI 伺服器或閘道器與 WSGI 應用程式物件之間的通訊,以檢查雙方是否符合協議。

請注意,此實用程式不保證完全符合 PEP 3333;此模組未出現錯誤並不一定意味著不存在錯誤。但是,如果此模組確實產生了錯誤,那麼幾乎可以肯定伺服器或應用程式不是 100% 符合的。

此模組基於 Ian Bicking 的“Python Paste”庫中的 paste.lint 模組。

wsgiref.validate.validator(application)

封裝 application 並返回一個新的 WSGI 應用程式物件。返回的應用程式會將所有請求轉發給原始的 application,並將檢查 application 和呼叫它的伺服器是否都符合 WSGI 規範和 RFC 2616

任何檢測到的不一致都會導致 AssertionError 被引發;但是請注意,這些錯誤的具體處理方式取決於伺服器。例如,wsgiref.simple_server 和其他基於 wsgiref.handlers 的伺服器(未覆蓋錯誤處理方法以執行其他操作)將簡單地輸出錯誤訊息,並將回溯轉儲到 sys.stderr 或其他錯誤流中。

此包裝器也可能使用 warnings 模組生成輸出,以指示有疑問但可能並未被 PEP 3333 實際禁止的行為。除非使用 Python 命令列選項或 warnings API 抑制,否則任何此類警告都將寫入 sys.stderr不是 wsgi.errors,除非它們恰好是同一個物件)。

用法示例:

from wsgiref.validate import validator
from wsgiref.simple_server import make_server

# Our callable object which is intentionally not compliant to the
# standard, so the validator is going to break
def simple_app(environ, start_response):
    status = '200 OK'  # HTTP Status
    headers = [('Content-type', 'text/plain')]  # HTTP Headers
    start_response(status, headers)

    # This is going to break because we need to return a list, and
    # the validator is going to inform us
    return b"Hello World"

# This is the application wrapped in a validator
validator_app = validator(simple_app)

with make_server('', 8000, validator_app) as httpd:
    print("Listening on port 8000....")
    httpd.serve_forever()

wsgiref.handlers – 伺服器/閘道器基類

此模組提供了用於實現 WSGI 伺服器和閘道器的基本處理程式類。這些基本類處理與 WSGI 應用程式通訊的大部分工作,只要它們給定一個類似 CGI 的環境,以及輸入、輸出和錯誤流。

class wsgiref.handlers.CGIHandler

透過 sys.stdinsys.stdoutsys.stderros.environ 進行基於 CGI 的呼叫。當您有一個 WSGI 應用程式並希望將其作為 CGI 指令碼執行時,這很有用。只需呼叫 CGIHandler().run(app),其中 app 是您希望呼叫的 WSGI 應用程式物件。

這個類是 BaseCGIHandler 的子類,它將 wsgi.run_once 設定為 true,wsgi.multithread 設定為 false,wsgi.multiprocess 設定為 true,並且始終使用 sysos 獲取必要的 CGI 流和環境。

class wsgiref.handlers.IISCGIHandler

一個 CGIHandler 的專用替代品,用於部署在 Microsoft 的 IIS Web 伺服器上,但沒有設定 config allowPathInfo 選項 (IIS>=7) 或 metabase allowPathInfoForScriptMappings (IIS<7) 的情況。

預設情況下,IIS 會給出一個 PATH_INFO,該 PATH_INFO 會在前面重複 SCRIPT_NAME,從而導致希望實現路由的 WSGI 應用程式出現問題。此處理程式會剝離任何此類重複路徑。

IIS 可以配置為傳遞正確的 PATH_INFO,但這會導致另一個錯誤,即 PATH_TRANSLATED 不正確。幸運的是,這個變數很少使用,並且 WSGI 並不保證。然而,在 IIS<7 上,設定只能在虛擬主機級別進行,影響所有其他指令碼對映,其中許多在暴露於 PATH_TRANSLATED 錯誤時會中斷。因此,IIS<7 幾乎從不部署此修復(即使 IIS7 也很少使用它,因為仍然沒有使用者介面)。

CGI 程式碼無法判斷是否設定了該選項,因此提供了一個單獨的處理程式類。它的使用方式與 CGIHandler 相同,即透過呼叫 IISCGIHandler().run(app),其中 app 是您希望呼叫的 WSGI 應用程式物件。

在 3.2 版本加入。

class wsgiref.handlers.BaseCGIHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)

類似於 CGIHandler,但不是使用 sysos 模組,CGI 環境和 I/O 流被顯式指定。multithreadmultiprocess 值用於設定處理程式例項執行的任何應用程式的 wsgi.multithreadwsgi.multiprocess 標誌。

此類是 SimpleHandler 的子類,旨在與 HTTP “源伺服器”以外的軟體一起使用。如果您正在編寫使用 Status: 頭髮送 HTTP 狀態的閘道器協議實現(例如 CGI、FastCGI、SCGI 等),您可能希望子類化此協議而不是 SimpleHandler

class wsgiref.handlers.SimpleHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)

類似於 BaseCGIHandler,但專為與 HTTP 源伺服器一起使用而設計。如果您正在編寫 HTTP 伺服器實現,您可能希望子類化此協議而不是 BaseCGIHandler

這個類是 BaseHandler 的子類。它重寫了 __init__()get_stdin()get_stderr()add_cgi_vars()_write()_flush() 方法,以支援透過建構函式顯式設定環境和流。提供的環境和流儲存在 stdinstdoutstderrenviron 屬性中。

stdoutwrite() 方法應該完整地寫入每個塊,就像 io.BufferedIOBase

class wsgiref.handlers.BaseHandler

這是一個用於執行 WSGI 應用程式的抽象基類。每個例項將處理單個 HTTP 請求,儘管原則上您可以建立一個可重用於多個請求的子類。

BaseHandler 例項只有一個供外部使用的方法

run(app)

執行指定的 WSGI 應用程式 app

在執行應用程式的過程中,所有其他 BaseHandler 方法都由這個方法呼叫,因此它們主要用於允許自定義過程。

以下方法必須在子類中重寫

_write(data)

將位元組 data 緩衝以傳輸給客戶端。如果此方法實際傳輸資料,則可以;BaseHandler 只是將寫入和重新整理操作分開,以便在底層系統實際有這種區別時提高效率。

_flush()

強制將緩衝資料傳輸到客戶端。如果此方法是空操作(即如果 _write() 實際傳送資料),則可以。

get_stdin()

返回一個與 InputStream 相容的物件,適用於作為當前正在處理的請求的 wsgi.input

get_stderr()

返回一個與 ErrorStream 相容的物件,適用於作為當前正在處理的請求的 wsgi.errors

add_cgi_vars()

將當前請求的 CGI 變數插入到 environ 屬性中。

以下是您可能希望重寫的一些其他方法和屬性。但是,此列表僅為摘要,不包括所有可以重寫的方法。在嘗試建立自定義 BaseHandler 子類之前,您應該查閱文件字串和原始碼以獲取更多資訊。

用於自定義 WSGI 環境的屬性和方法

wsgi_multithread

用於 wsgi.multithread 環境變數的值。在 BaseHandler 中預設為 true,但在其他子類中可能有不同的預設值(或由建構函式設定)。

wsgi_multiprocess

用於 wsgi.multiprocess 環境變數的值。在 BaseHandler 中預設為 true,但在其他子類中可能有不同的預設值(或由建構函式設定)。

wsgi_run_once

用於 wsgi.run_once 環境變數的值。在 BaseHandler 中預設為 false,但 CGIHandler 預設將其設定為 true。

os_environ

包含在每個請求的 WSGI 環境中的預設環境變數。預設情況下,這是匯入 wsgiref.handlersos.environ 的副本,但子類可以在類或例項級別建立自己的副本。請注意,該字典應被視為只讀,因為預設值在多個類和例項之間共享。

server_software

如果設定了 origin_server 屬性,則此屬性的值用於設定預設的 SERVER_SOFTWARE WSGI 環境變數,以及在 HTTP 響應中設定預設的 Server: 頭。對於不是 HTTP 源伺服器的處理程式(例如 BaseCGIHandlerCGIHandler),它將被忽略。

3.3 版本發生變化: “Python”一詞被替換為特定於實現的術語,如“CPython”、“Jython”等。

get_scheme()

返回當前請求正在使用的 URL 方案。預設實現使用 wsgiref.util 中的 guess_scheme() 函式,根據當前請求的 environ 變數猜測方案應該是“http”還是“https”。

setup_environ()

environ 屬性設定為完全填充的 WSGI 環境。預設實現使用所有上述方法和屬性,以及 get_stdin()get_stderr()add_cgi_vars() 方法以及 wsgi_file_wrapper 屬性。它還會插入一個 SERVER_SOFTWARE 鍵(如果不存在),只要 origin_server 屬性為真且 server_software 屬性已設定。

用於自定義異常處理的方法和屬性

log_exception(exc_info)

在伺服器日誌中記錄 exc_info 元組。exc_info 是一個 (type, value, traceback) 元組。預設實現只是將回溯寫入請求的 wsgi.errors 流並重新整理它。子類可以重寫此方法以更改格式或重定向輸出、將回溯郵件傳送給管理員,或執行任何其他可能被認為合適的動作。

traceback_limit

預設 log_exception() 方法輸出的回溯中包含的最大幀數。如果為 None,則包含所有幀。

error_output(environ, start_response)

此方法是一個 WSGI 應用程式,用於為使用者生成錯誤頁面。它僅在將標頭髮送到客戶端之前發生錯誤時呼叫。

此方法可以使用 sys.exception() 訪問當前錯誤,並且在呼叫 start_response 時應將該資訊傳遞給它(如 PEP 3333 的“錯誤處理”部分所述)。特別是,可呼叫物件 start_response 應遵循 StartResponse 協議。

預設實現僅使用 error_statuserror_headerserror_body 屬性生成輸出頁面。子類可以重寫此方法以生成更動態的錯誤輸出。

但是請注意,從安全形度來看,不建議將診斷資訊直接顯示給任何普通使用者;理想情況下,您應該採取特殊措施來啟用診斷輸出,這就是預設實現不包含任何診斷資訊的原因。

error_status

用於錯誤響應的 HTTP 狀態。這應該是一個狀態字串,如 PEP 3333 中定義的;它預設為 500 狀態碼和訊息。

error_headers

用於錯誤響應的 HTTP 頭。這應該是一個 WSGI 響應頭列表((name, value) 元組),如 PEP 3333 中所述。預設列表只將內容型別設定為 text/plain

error_body

錯誤響應主體。這應該是一個 HTTP 響應主體位元組串。它預設為純文字“A server error occurred. Please contact the administrator.”

用於 PEP 3333 的“可選平臺特定檔案處理”功能的方法和屬性

wsgi_file_wrapper

一個 wsgi.file_wrapper 工廠,與 wsgiref.types.FileWrapper 相容,或 None。此屬性的預設值是 wsgiref.util.FileWrapper 類。

sendfile()

重寫以實現特定於平臺的檔案傳輸。此方法僅在應用程式的返回值是 wsgi_file_wrapper 屬性指定的類的例項時呼叫。如果它能夠成功傳輸檔案,則應返回一個真值,以便不會執行預設的傳輸程式碼。此方法的預設實現只返回一個假值。

雜項方法和屬性

origin_server

如果處理程式的 _write()_flush() 正用於直接與客戶端通訊,而不是透過需要特殊 Status: 頭中的 HTTP 狀態的類 CGI 閘道器協議進行通訊,則此屬性應設定為 true。

此屬性在 BaseHandler 中預設為 true,但在 BaseCGIHandlerCGIHandler 中為 false。

http_version

如果 origin_server 為 true,則此字串屬性用於設定傳送給客戶端的響應的 HTTP 版本。它預設為 "1.0"

wsgiref.handlers.read_environ()

將 CGI 變數從 os.environ 轉碼為 PEP 3333 “Unicode 中的位元組”字串,並返回一個新字典。此函式由 CGIHandlerIISCGIHandler 使用,以替代直接使用 os.environ,因為在所有使用 Python 3 的平臺和 Web 伺服器上,os.environ 不一定符合 WSGI 規範——特別是那些作業系統的實際環境是 Unicode(即 Windows),或者環境是位元組但 Python 用於解碼的系統編碼不是 ISO-8859-1(例如使用 UTF-8 的 Unix 系統)。

如果您正在實現自己的基於 CGI 的處理程式,您可能希望使用此例程,而不是直接從 os.environ 中複製值。

在 3.2 版本加入。

wsgiref.types – 用於靜態型別檢查的 WSGI 型別

此模組提供了 PEP 3333 中描述的用於靜態型別檢查的各種型別。

在 3.11 版本中新增。

class wsgiref.types.StartResponse

一個 typing.Protocol,描述 start_response() 可呼叫物件(PEP 3333)。

wsgiref.types.WSGIEnvironment

描述 WSGI 環境字典的類型別名。

wsgiref.types.WSGIApplication

描述 WSGI 應用程式可呼叫物件的類型別名。

class wsgiref.types.InputStream

一個 typing.Protocol,描述一個 WSGI 輸入流

class wsgiref.types.ErrorStream

一個 typing.Protocol,描述一個 WSGI 錯誤流

class wsgiref.types.FileWrapper

一個 typing.Protocol,描述一個 檔案包裝器。有關此協議的具體實現,請參閱 wsgiref.util.FileWrapper

示例

這是一個可工作的“Hello World”WSGI 應用程式,其中 start_response 可呼叫物件應遵循 StartResponse 協議

"""
Every WSGI application must have an application object - a callable
object that accepts two arguments. For that purpose, we're going to
use a function (note that you're not limited to a function, you can
use a class for example). The first argument passed to the function
is a dictionary containing CGI-style environment variables and the
second variable is the callable object.
"""
from wsgiref.simple_server import make_server


def hello_world_app(environ, start_response):
    status = "200 OK"  # HTTP Status
    headers = [("Content-type", "text/plain; charset=utf-8")]  # HTTP Headers
    start_response(status, headers)

    # The returned object is going to be printed
    return [b"Hello World"]

with make_server("", 8000, hello_world_app) as httpd:
    print("Serving on port 8000...")

    # Serve until process is killed
    httpd.serve_forever()

一個 WSGI 應用程式的示例,用於提供當前目錄,接受命令列上可選的目錄和埠號(預設:8000)

"""
Small wsgiref based web server. Takes a path to serve from and an
optional port number (defaults to 8000), then tries to serve files.
MIME types are guessed from the file names, 404 errors are raised
if the file is not found.
"""
import mimetypes
import os
import sys
from wsgiref import simple_server, util


def app(environ, respond):
    # Get the file name and MIME type
    fn = os.path.join(path, environ["PATH_INFO"][1:])
    if "." not in fn.split(os.path.sep)[-1]:
        fn = os.path.join(fn, "index.html")
    mime_type = mimetypes.guess_file_type(fn)[0]

    # Return 200 OK if file exists, otherwise 404 Not Found
    if os.path.exists(fn):
        respond("200 OK", [("Content-Type", mime_type)])
        return util.FileWrapper(open(fn, "rb"))
    else:
        respond("404 Not Found", [("Content-Type", "text/plain")])
        return [b"not found"]


if __name__ == "__main__":
    # Get the path and port from command-line arguments
    path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 8000

    # Make and start the server until control-c
    httpd = simple_server.make_server("", port, app)
    print(f"Serving {path} on port {port}, control-C to stop")
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("Shutting down.")
        httpd.server_close()