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