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