"wsgiref" --- WSGI 工具與參考實作
*********************************

**原始碼：**Lib/wsgiref

======================================================================

警告:

  "wsgiref" is a reference implementation and is not recommended for
  production. The module only implements basic security checks.

網頁伺服器閘道介面 (WSGI) 是一個標準介面，用於連接網頁伺服器軟體與使用
Python 撰寫的網頁應用程式，擁有一個標準介面使得支援 WSGI 的應用程式可
以與多個不同的網頁伺服器運行。

只有網頁伺服器與程式框架的作者需要瞭解 WSGI 設計的每個細節與邊角案例，
你並不需要為了安裝 WSGI 應用程式或是使用現有框架撰寫網頁應用程式而必須
理解每個細節。

"wsgiref" 是 WSGI 規格的參考實作，可用於新增 WSGI 來支援網頁伺服器或框
架，它提供操作 WSGI 環境變數以及回應標頭的工具，用於實作 WSGI 伺服器的
基本類別，提供用於示範 HTTP 伺服器的 WSGI 應用程式、靜態型別檢查、以及
驗證 WSGI 伺服器與應用程式是否符合 WSGI 規格的驗證工具 (**PEP 3333**)
。

參閱 wsgi.readthedocs.io 更多 WSGI 相關資訊，以及教學連結與其他資源。


"wsgiref.util" -- WSGI 環境工具
===============================

這個模組提供許多用於處理 WSGI 環境運作的功能。WSGI 環境是一個包含 HTTP
請求變數的字典，如 **PEP 3333** 所述。所有接受 *environ* 的參數的函式
都需要提供符合 WSGI 標準的字典；請參閱 **PEP 3333** 取得詳細規格，以及
"WSGIEnvironment" 取得可用於使用型別註釋的型別別名。

wsgiref.util.guess_scheme(environ)

   透過檢查 *environ* 字典中的 "HTTPS" 環境變數，回傳
   "wsgi.url_scheme" 應該是 "http" 或 "https" 的猜測。回傳值為一個字串
   。

   當建立一個包裝 CGI 或類似 FastCGI 的 CGI-like 協定閘道時，此函式非
   常有用。例如 FastCGI，通常提供這類協定的伺服器在透過 SSL 接收到請求
   時會包含 "1"，"yes"，或 "on" 的 "HTTPS" 變數，因此，如果找到這樣的
   值，此函式回傳 "https"，否則回傳 "http"。

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

   根據 **PEP 3333** 中 "URL Reconstruction" 章節所找到的演算法，回傳
   完整的請求 URI，可選擇性的包含查詢字串，如果 *include_query* 設為
   false，查詢字串不會被包含在結果的 URI 中。

wsgiref.util.application_uri(environ)

   類似於 "request_uri()"，但忽略 "PATH_INFO" 和 "QUERY_STRING" 變數。
   結果是請求地址的應用程式物件的的基本 URI。

wsgiref.util.shift_path_info(environ)

   將單一名稱從 "PATH_INFO" 移到 "SCRIPT_NAME" 並回傳該名稱。*environ*
   字典會在適當時機被 *modified*；如果你需要保留原始完好無損的
   "PATH_INFO" 或 "SCRIPT_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" 和結尾為 "/x/" 的 URIs
   。

wsgiref.util.setup_testing_defaults(environ)

   為測試目的，以簡單的預設值更新 *environ* 。

   這個程式新增 WSGI 所需的各種參數，包括 "HTTP_HOST"、"SERVER_NAME"、
   "SERVER_PORT"、"REQUEST_METHOD"、"SCRIPT_NAME"、"PATH_INFO"，以及所
   有 **PEP 3333** 定義的 "wsgi.*" 變數，它只提供預設值，並且不會取代
   現有的這些變數設定。

   這個程式目的為了讓 WSGI 伺服器和應用程式的單元測試更容易建置虛擬環
   境。實際的 WSGI 伺服器或應用程式不應該使用它，因為所產生的數據是假
   的！

   Example usage (see also "demo_app()" for another example):

      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 "Hop-by-
   Hop" 標頭，則回傳 "True"。

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

   "wsgiref.types.FileWrapper" 協定的具體實作，用於將類檔案物件轉換為
   *iterator*。產生的物件是 *iterable*。當物件進行疊代時，將可選的
   *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])

   建立一個類似對映物件並包裝 *headers*，並且必須是符合 **PEP 3333**
   描述的 name/value 元組的標頭串列。*headers* 的預設值是一個空串列。

   "Headers" 物件支援典型對映操作包括 "__getitem__()"、"get()"、
   "__setitem__()"、"setdefault()"、"__delitem__()" 以及
   "__contains__()"。對於這些方法中的每一個，鍵是標頭名稱（以不區分大
   小寫方式處理），而值則是與該標頭名稱關聯的第一個值。設定標頭會刪除
   該標頭的所有現有值，然後將新值添加到包裝的標頭串列末尾。標頭的現有
   順序通常保持不變，新標頭會添加到包裝串列的末尾。

   不同於字典，當你嘗試取得或刪除包裝的標頭串列不存在的鍵，"Headers"
   物件不會引發例外錯誤。取得不存在的標頭只會回傳 "None"，而刪除不存在
   的標頭則不會有任何效果。

   "Headers" 物件還支援 "keys()"、"values()"、和 "items()" 方法。由
   "keys()" 和 "items()" 回傳的串列在存在多值標頭時可能會包含相同的鍵
   。"Headers" 物件的 "len()" 與 "items()" 的長度相同，也與包裝標頭串
   列的長度相同。實際上，"items()" 方法只是回傳包裝的標頭串列的副本。

   對 "Headers" 物件呼叫 "bytes()" 會回傳適合作為 HTTP 傳輸回應標頭的
   格式化的位元組字串。每個標頭都與其值一起置於一行上，由冒號與空格分
   隔。每行以回車（carriage return）和換行（line feed）結束，而該位元
   組字串則以空行結束。

   除了對映介面和格式化功能外，"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 伺服器監聽 *host* 和 *port*，接受 *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 應用程式非常有用。

   The *start_response* callable should follow the "StartResponse"
   protocol.

class wsgiref.simple_server.WSGIServer(server_address, RequestHandlerClass)

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

   通常你不需要呼叫這個建構函式（constructor），因為 "make_server()"
   函式可以為你處理所有細節。

   "WSGIServer" 是 "http.server.HTTPServer" 的子類別，因此它的所有方法
   （例如 "serve_forever()" 和 "handle_request()"）都可用。
   "WSGIServer" 也提供這些特定於 WSGI 的方法：

   set_app(application)

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

   get_app()

      回傳目前設定應用程式的可呼叫物件。

   然而，通常情況下你不需要去使用這些額外方法，因為 "set_app()" 通常會
   被 "make_server()" 呼叫而 "get_app()" 主要存在於請求處理程式（
   handler）實例的好處上。

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

   為給定的 *request*（即一個 socket）、*client_address*（一個
   "(host,port)" 位元組）、*server* ("WSGIServer" 實例) 建立一個 HTTP
   處理程式（handler）。

   你不需要直接建立這個類別的實例；它們會在需要時由 "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" 類別來建立處置
      程式（handler）實例來實作實際 WSGI 應用程式介面。


"wsgiref.validate" --- WSGI 符合性檢查
======================================

當建立新的 WSGI 應用程式物件、框架、伺服器、或是中介軟體（middleware）
時，使用 "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.handlers" 的
   "wsgiref.simple_server" 以及其他伺服器（未覆蓋錯誤處理方法以執行其
   他操作的伺服器）將僅輸出一條錯誤訊息，指示發生錯誤，並將回溯訊息輸
   出到 "sys.stderr" 或是其他錯誤串流。

   這個包裝器也可以使用 "warnings" 模組生成輸出去指示一些可能有疑慮但
   實際上可能不會被 **PEP 3333** 禁止的行為。除非使用 Python 命令列選
   項或 "warnings" API，抑制了這些警告，否則這類警告將被寫入到
   "sys.stderr"（*not* "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 伺服器和閘道的基礎處理程式（handler）類別。這些
基底類別處理程式大部分與 WSGI 應用程式通訊的工作，只要它們被提供 CGI-
like 環境，以及輸入、輸出和錯誤串流。

class wsgiref.handlers.CGIHandler

   這是基於 CGI 的呼叫方式並透過 "sys.stdin"、"sys.stdout"、
   "sys.stderr" 和 "os.environ"。當你擁有一個 WSGI 應用程式並希望將其
   作為 CGI 腳本運行時是很有用的。只需叫用 "CGIHandler().run(app)"，其
   中 "app" 是你希望叫用的 WSGI 應用程式物件。

   這個類別是 "BaseCGIHandler" 的子類別將 "wsgi.run_once" 設置為 true
   ，"wsgi.multithread" 設置為 false，並將 "wsgi.multiprocess" 設置為
   true，並且始終使用 "sys" 和 "os" 來取得所需的 CGI 串流以及環境。

class wsgiref.handlers.IISCGIHandler

   這是用於在 Microsoft 的 IIS 網頁伺服器上部署時使用的 "CGIHandler"
   的一個專門替代選擇，無需設置 config 的 allowPathInfo 選項（IIS>=7）
   ，或 metabase 的 allowPathInfoForScriptMappings 選項（IIS<7）。

   預設情況下，IIS 提供的 "PATH_INFO" 會在前面複製 "SCRIPT_NAME"，對於
   希望實作路由的 WSGI 應用程式造成問題。這個處理程式（handler）會移除
   任何這樣的重複路徑。

   IIS 可以配置去傳遞正確的 "PATH_INFO"，但這會導致 "PATH_TRANSLATED"
   是錯誤的問題。幸運的是這個變數很少被使用並且不受 WSGI 保證。然而，
   在 IIS<7 上，這個設置只能在虛擬主機層級進行，影響所有其他腳本的對映
   ，其中許多在暴露 "PATH_TRANSLATED" 問題時會中斷。由於這個原因幾乎從
   不會使用修復的 IIS<7（即使是 IIS7 也很少使用它，因為它仍然沒有相應
   的 UI）。

   CGI 程式碼無法知道是否已設置該選項，因此提供了一個獨立的處理程式（
   handler）類別。它的使用方式與 "CGIHandler" 相同，即透過呼叫
   "IISCGIHandler().run(app)" 來使用，其中 "app" 是你希望叫用的 WSGI
   應用程式物件。

   在 3.2 版被加入.

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

   類似於 "CGIHandler"，但不是使用 "sys" 和 "os" 模組，而是明確指定
   CGI 環境與 I/O 串流。*multithread* 和 *multiprocess* 值用於設置由處
   理程式（handler）實例運行的任何應用程式的旗標。

   這個類別是專門為除了 HTTP "origin servers" 以外的軟體一起使用的
   "SimpleHandler" 的子類別。如果你正在撰寫一個使用 "Status:" 標頭來發
   送 HTTP 狀態的閘道協定實作（例如 CGI、FastCGI、SCGI 等），你可能會
   想要子類化這個類別來替代 "SimpleHandler"。

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

   類似於 "BaseCGIHandler"，但是被設計使用在 HTTP origin 伺服器。如果
   你正在撰寫 HTTP 伺服器的實作，你可能會想要子類別化這個類別來替代
   "BaseCGIHandler"。

   這個類別是 "BaseHandler" 的子類別。它透過建構函式去覆寫
   "__init__()"、"get_stdin()"、"get_stderr()"、"add_cgi_vars()"、
   "_write()"、和 "_flush()" 方法來明確提供設置環境與串流。提供的環境
   與串流被儲存在 "stdin"、"stdout"、"stderr"、和 "environ" 環境中。

   *stdout* 的 "write()" 方法應該完整地寫入每個塊（chunk），像是
   "io.BufferedIOBase"。

class wsgiref.handlers.BaseHandler

   這是一個運行 WSGI 應用程式的抽象基底類別。每個實例將處理單個 HTTP
   請求，儘管原則上你可以建立一個可重用於多個請求的子類別。

   "BaseHandler" 實例只有一個供外部使用的方法：

   run(app)

      運行指定 WSGI 應用程式，*app*。

   此方法在運行應用程式的過程中叫用了所有其他 "BaseHandler" 的方法，因
   此這些方法主要存在是為了允許自訂整個過程。

   以下方法必須在子類別中覆寫：

   _write(data)

      緩衝要傳送給用戶端的位元組 *data*。如果這個方法實際上傳送了數據
      也是可以的；當底層系統實際具有這種區分時，"BaseHandler" 為了更好
      的效能進而分離寫入和刷新操作。

   _flush()

      強制將緩衝數據傳送到用戶端。如果這是一個無操作（no-op）的方法（
      即，如果 "_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.handlers" 時的 "os.environ" 副本，但子類別可以在類別
      或實例層級建立自己的副本。注意字典應該被視為唯讀，因為預設值在多
      個類別與實例中共享。

   server_software

      如果設置 "origin_server" 屬性，則此屬性的值將用於設置預設的
      "SERVER_SOFTWARE" WSGI 環境變數，並且還將用於設置 HTTP 回應中的
      預設 "Server:" 標頭。對於不是 HTTP origin 伺服器的處置程式（例如
      "BaseCGIHandler" 和 "CGIHandler"），此屬性將被忽略。

      在 3.3 版的變更: 將術語 "Python" 替換為特定實作的術語，如
      "CPython"、"Jython" 等。

   get_scheme()

      回傳用於目前請求的 URL scheme。預設的實作使用 "wsgiref.util" 中
      的 "guess_scheme()" 函式去猜測 scheme 是 "http" 或是 "https"，基
      於目前請求的 "environ" 變數。

   setup_environ()

      將 "environ" 屬性設置為完全填充的 WSGI 環境。預設的實作使用上述
      所有方法和屬性，以及 "get_stdin()"、"get_stderr()" 和
      "add_cgi_vars()" 方法以及 "wsgi_file_wrapper" 屬性。如果不呈現它
      也會插入一個 "SERVER_SOFTWARE" 關鍵字，只要 "origin_server" 屬性
      是一個 true 值並且 "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()" 存取目前的錯誤，當呼叫它（如 **PEP
      3333** 的 "Error Handling" 部分所描述）時應該傳遞資訊給
      *start_response*。特別是 *start_response* 可呼叫物件應該遵循
      "StartResponse" 協定。

      預設的實作只是使用 "error_status"、"error_headers" 和
      "error_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** 中的 "Optional Platform-Specific File Handling"
   功能的方法和屬性：

   wsgi_file_wrapper

      一個 "wsgi.file_wrapper" 工廠函式（factory），與
      "wsgiref.types.FileWrapper" 相容，或者為 "None"。這個屬性的預設
      值是 "wsgiref.util.FileWrapper" 類別。

   sendfile()

      覆蓋以實作特定平台的檔案傳輸。只有當應用程式的回傳值是由
      "wsgi_file_wrapper" 屬性指定的類別實例時才會呼叫此方法。如果它能
      夠成功傳輸檔案應該回傳一個 true 值，以便不執行預設的傳輸程式碼。
      該方法的預設實作只回傳一個 false 值。

   其他方法和屬性：

   origin_server

      這個屬性應該被設置為 true 值，如果處理程式（handler）的
      "_write()" 和 "_flush()" 被用於直接與用戶端通訊，而不是透過 CGI-
      like 的閘道協定希望 HTTP 狀態在特殊的 "Status:" 標頭中。

      這個屬性在 "BaseHandler" 預設值為 true，但是在 "BaseCGIHandler"
      和 "CGIHandler" 為 false。

   http_version

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

wsgiref.handlers.read_environ()

   從 "os.environ" 轉碼 CGI 變數到 **PEP 3333** 中的 "bytes in
   unicode" 字串，並回傳一個新字典。這個函式被 "CGIHandler" 和
   "IISCGIHandler" 使用來直接替代 "os.environ"，在所有平台和使用
   Python 3 的網頁伺服器上不一定符合 WSGI 標準，具體來說，在 OS 的實際
   環境是 Unicode（例如 Windows）的情況下，或者在環境是位元組的情況下
   ，但 Python 用於解碼它的系統編碼不是 ISO-8859-1 （例如使用 UTF-8 的
   Unix 系統）。

   如果你自己正在實作 CGI-based 處理程式（handler），你可能想要使用這
   個函式來替換單純直接從 "os.environ" 中複製值。

   在 3.2 版被加入.


"wsgiref.types" -- 用於靜態型別檢查的 WSGI 型別
===============================================

這個模組提供在 **PEP 3333** 中所描述的各種用於靜態型別檢查的型別。

在 3.11 版被加入.

class wsgiref.types.StartResponse

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

wsgiref.types.WSGIEnvironment

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

wsgiref.types.WSGIApplication

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

class wsgiref.types.InputStream

   一個描述 **WSGI 輸入串流**的 "typing.Protocol"。

class wsgiref.types.ErrorStream

   一個描述 **WSGI 錯誤串流**的 "typing.Protocol"。

class wsgiref.types.FileWrapper

   一個描述**檔案包裝器**的 "typing.Protocol"。請參閱
   "wsgiref.util.FileWrapper" 來瞭解此協定的具體實作。


範例
====

This is a working "Hello World" WSGI application, where the
*start_response* callable should follow the "StartResponse" protocol:

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