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 接收到請求時,會包含一個值為“1”、“yes”或“on”的 HTTPS 變數。因此,如果找到這樣的值,此函式將返回“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 應用程式。例如,如果 /foo 處有一個 WSGI 應用程式,並且請求 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 伺服器或應用程式不應使用它,因為資料是虛假的!

用法示例

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’ 是 RFC 2616 定義的 HTTP/1.1 “逐跳” 標頭,則返回 True

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

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

如果 filelikeclose() 方法,則返回的物件也將有一個 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])

建立一個類似對映的物件,包裝 headers,它必須是 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.utilshift_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 應用程式。

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 (即套接字)、client_address (一個 (host,port) 元組)和 serverWSGIServer 例項)建立一個 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

當部署在 Microsoft 的 IIS Web 伺服器上,而沒有設定 config allowPathInfo 選項(IIS>=7)或 metabase allowPathInfoForScriptMappings(IIS<7)時,CGIHandler 的一個專門的替代方案。

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

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

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 時應將該資訊傳遞給 start_response (如 PEP 3333 的“錯誤處理”部分中所述)。

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

但是,從安全形度來看,不建議向任何舊使用者輸出診斷資訊;理想情況下,您應該必須執行一些特殊操作才能啟用診斷輸出,這就是為什麼預設實現不包含任何診斷輸出的原因。

error_status

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

error_headers

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

error_body

錯誤響應正文。這應該是 HTTP 響應正文位元組串。它預設為純文字“發生了伺服器錯誤。請聯絡管理員。”

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

wsgi_file_wrapper

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

sendfile()

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

其他方法和屬性

origin_server

如果處理程式的 _write()_flush() 用於直接與客戶端通訊,而不是透過 CGI 式的閘道器協議(該協議希望 HTTP 狀態位於特殊的 Status: 標頭中),則應將此屬性設定為真值。

此屬性在 BaseHandler 中的預設值為真,但在 BaseCGIHandlerCGIHandler 中為假。

http_version

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

wsgiref.handlers.read_environ()

將 CGI 變數從 os.environ 轉碼為 PEP 3333 “位元組轉換為 Unicode” 字串,並返回一個新的字典。此函式由 CGIHandlerIISCGIHandler 使用,以替代直接使用 os.environ,因為在所有平臺和使用 Python 3 的 Web 伺服器上,它不一定是符合 WSGI 的——特別是那些 OS 的實際環境是 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 應用程式

"""
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()