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 应用程序。例如,如果在 /foo 处有一个 WSGI 应用程序,并且请求 URI 路径是 /foo/bar/baz,并且 /foo 处的 WSGI 应用程序调用 shift_path_info(),它将接收字符串“bar”,并且环境将被更新为适合于传递给 /foo/bar 处的 WSGI 应用程序。也就是说,SCRIPT_NAME 将从 /foo 更改为 /foo/barPATH_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”是 HTTP/1.1“逐跳”标头(由 RFC 2616 定义),则返回 True

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

用于将类文件对象转换为 迭代器wsgiref.types.FileWrapper 协议的具体实现。生成的对象是 可迭代 的。在迭代对象时,可选的 blksize 参数将被重复传递给 filelike 对象的 read() 方法以获取要生成的字节串。当 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 中描述的标头名称/值元组列表。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 应用程序非常有用。

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 服务器和网关的基本处理程序类。只要为这些基类提供类似 CGI 的环境以及输入、输出和错误流,它们就可以处理与 WSGI 应用程序通信的大部分工作。

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 在前面复制了 SCRIPT_NAME,这会导致希望实现路由的 WSGI 应用程序出现问题。此处理程序会删除任何此类重复的路径。

可以将 IIS 配置为传递正确的 PATH_INFO,但这会导致另一个错误,即 PATH_TRANSLATED 错误。幸运的是,这个变量很少使用,并且 WSGI 不保证它。但是,在 IIS<7 上,该设置只能在虚拟主机级别进行,影响所有其他脚本映射,其中许多在暴露于 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 属性。只要 origin_server 属性为真值且设置了 server_software 属性,它还会插入一个 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 的“错误处理”部分所述)。

默认实现仅使用 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

wsgiref.types.FileWrapper 兼容的 wsgi.file_wrapper 工厂,或 None。此属性的默认值为 wsgiref.util.FileWrapper 类。

sendfile()

覆盖以实现特定于平台的文件传输。仅当应用程序的返回值是 wsgi_file_wrapper 属性指定的类的实例时,才会调用此方法。如果它能够成功传输文件,则它应该返回真值,以便不会执行默认的传输代码。此方法的默认实现仅返回假值。

其他方法和属性

origin_server

如果处理程序的 _write()_flush() 用于直接与客户端通信,而不是通过希望在特殊 Status: 标头中包含 HTTP 状态的类似 CGI 的网关协议进行通信,则应将此属性设置为真值。

此属性在 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 服务器上不一定符合 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

描述 start_response() 可调用对象的 typing.ProtocolPEP 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

示例

这是一个有效的“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_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()