20.4. wsgiref — WSGIUtil 和参考实现

2.5 版的新Function。

Web 服务器网关接口(WSGI)是 Web 服务器软件和用 Python 编写的 Web 应用程序之间的标准接口。具有标准的界面可以轻松地将支持 WSGI 的应用程序与许多不同的 Web 服务器一起使用。

只有 Web 服务器和编程框架的作者才需要了解 WSGI 设计的每个细节和特殊情况。您无需仅安装 WSGI 应用程序或使用现有框架编写 Web 应用程序就了解 WSGI 的每个细节。

wsgiref是 WSGI 规范的参考实现,可用于将 WSGI 支持添加到 Web 服务器或框架。它提供用于处理 WSGI 环境变量和响应 Headers 的 Util,用于实现 WSGI 服务器的 Base Class,为 WSGI 应用程序提供服务的演示 HTTP 服务器以及用于检查 WSGI 服务器和应用程序是否符合 WSGI 规范( PEP 333)的验证工具。

有关 WSGI 的更多信息以及教程和其他资源的链接,请参见https://wsgi.readthedocs.org/

20.4.1. wsgiref.util – WSGI 环境 Util

该模块提供了用于 WSGI 环境的各种 Util Function。 WSGI 环境是包含 PEP 333中描述的 HTTP 请求变量的字典。所有带有* environ *参数的函数都希望提供符合 WSGI 的字典;请参阅 PEP 333了解详细说明。

当创建包装 CGI 或类似 CGI 的协议(如 FastCGI)的网关时,此Function很有用。通常,提供此类协议的服务器在pass SSL 接收到请求时将包括一个HTTPS变量,其值为“ 1”,“是”或“开”。因此,如果找到该值,此函数将返回“ https”,否则返回“ http”。

如果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 之间的区别。

此例程添加了 WSGI 所需的各种参数,包括HTTP_HOSTSERVER_NAMESERVER_PORTREQUEST_METHODSCRIPT_NAMEPATH_INFO以及所有 PEP 333定义的wsgi.*变量。它仅提供默认值,并且不替换这些变量的任何现有设置。

该例程旨在使 WSGI 服务器和应用程序的单元测试更容易设置虚拟环境。实际的 WSGI 服务器或应用程序都不应使用它,因为数据是伪造的!

Example usage:

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')]

    start_response(status, headers)

    ret = ["%s: %s\n" % (key, value)
           for key, value in environ.iteritems()]
    return ret

httpd = make_server('', 8000, simple_app)
print "Serving on port 8000..."
httpd.serve_forever()

除了上面的环境Function之外,wsgiref.util模块还提供了以下各种 Util:

如果* filelike 具有close()方法,则返回的对象也将具有close()方法,并且在调用时将调用 filelike *对象的close()方法。

Example usage:

from StringIO 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

20.4.2. wsgiref.headers – WSGI 响应头工具

该模块提供了一个单一类Headers,以便使用类似于 Map 的接口方便地操作 WSGI 响应 Headers。

Headers个对象支持典型的 Map 操作,包括getitem()get()setitem()setdefault()delitem()contains()has_key()。对于每种方法,键都是 Headers 名称(不区分大小写),并且值是与该 Headers 名称关联的第一个值。设置标题会删除该标题的所有现有值,然后在包装的标题列表的末尾添加一个新值。通常保留标题的现有 Sequences,将新的标题添加到包装列表的末尾。

与字典不同,当您try获取或删除包装的标题列表中没有的键时,Headers个对象不会引发错误。获取不存在的 Headers 只会返回None,而删除不存在的 Headers 则无济于事。

Headers个对象还支持keys()values()items()方法。如果存在多值 Headers,则keys()items()返回的列表可以多次包含同一键。 Headers对象的len()与其items()的长度相同,也与包装的 Headers 列表的长度相同。实际上,items()方法仅返回包装的 Headers 列表的副本。

Headers对象上调用str()返回适合于作为 HTTP 响应 Headers 传输的格式化字符串。每个 Headers 均以其值放在一行中,并用冒号和空格分隔。每行以回车和换行符结尾,字符串以空行结尾。

Headers对象除了具有 Map 界面和格式设置Function外,还具有以下方法用于查询和添加多值 Headers 以及添加具有 MIME 参数的 Headers:

返回的列表将按照它们在原始标题列表中出现或添加到此实例的 Sequences 进行排序,并且可能包含重复项。删除并重新插入的所有字段始终附加到标题列表中。如果不存在具有给定名称的字段,则返回一个空列表。

h.add_header('content-disposition', 'attachment', filename='bud.gif')

上面将添加一个标题,如下所示:

Content-Disposition: attachment; filename="bud.gif"

20.4.3. wsgiref.simple_server –简单的 WSGI HTTP 服务器

该模块实现了一个简单的 HTTP 服务器(基于BaseHTTPServer),该服务器为 WSGI 应用程序服务。每个服务器实例在给定的主机和端口上服务单个 WSGI 应用程序。如果要在单个主机和端口上提供多个应用程序,则应创建一个 WSGI 应用程序,该应用程序分析PATH_INFO来选择要为每个请求调用的应用程序。 (例如,使用wsgiref.util中的shift_path_info()函数。)

Example usage:

from wsgiref.simple_server import make_server, demo_app

httpd = make_server('', 8000, demo_app)
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()

通常不需要调用此构造函数,因为make_server()函数可以为您处理所有详细信息。

WSGIServerBaseHTTPServer.HTTPServer的子类,因此它的所有方法(例如serve_forever()handle_request())都可用。 WSGIServer还提供了这些特定于 WSGI 的方法:

但是,通常不需要使用这些其他方法,因为set_app()通常由make_server()调用,而get_app()主要是为了请求处理程序实例而存在。

您无需直接创建此类的实例; WSGIServer对象会根据需要自动创建它们。但是,您可以继承该类并将其作为* handler_class *提供给make_server()函数。在子类中重写的一些可能相关的方法:

20.4.4. wsgiref.validate — WSGI 一致性检查器

创建新的 WSGI 应用程序对象,框架,服务器或中间件时,使用wsgiref.validate验证新代码的一致性可能很有用。该模块提供了创建 WSGI 应用程序对象的Function,该Function验证 WSGI 服务器或网关与 WSGI 应用程序对象之间的通信,以检查双方的协议一致性。

请注意,该 Util 不能保证完全符合 PEP 333的要求;该模块中没有错误并不一定意味着不存在错误。但是,如果此模块确实产生错误,则实际上可以确定服务器或应用程序不是 100%兼容的。

该模块基于 Ian Bicking 的“ Python Paste”库中的paste.lint模块。

任何检测到的不符合项都会引发AssertionError;但是请注意,如何处理这些错误取决于服务器。例如,wsgiref.simple_server和其他基于wsgiref.handlers的服务器(不会覆盖错误处理方法以执行其他操作)将仅输出一条消息,指出发生了错误,并将回溯信息转储到sys.stderr或其他错误流。

该包装器还可以使用warnings模块生成输出,以指示可疑但 PEP 333可能实际上并未禁止的行为。除非使用 Python 命令行选项或warnings API 禁止它们,否则任何此类警告都将被写入sys.stderr(* not * wsgi.errors,除非它们恰好是同Pair象)。

Example usage:

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 "Hello World"

# This is the application wrapped in a validator
validator_app = validator(simple_app)

httpd = make_server('', 8000, validator_app)
print "Listening on port 8000...."
httpd.serve_forever()

20.4.5. wsgiref.handlers –服务器/网关基本类

该模块提供用于实现 WSGI 服务器和网关的基本处理程序类。这些 Base Class 可以处理与 WSGI 应用程序进行通信的大部分工作,只要它们具有类似 CGI 的环境以及 Importing,输出和错误流即可。

此类是BaseCGIHandler的子类,该子类将wsgi.run_once设置为 true,将wsgi.multithread设置为 false,并将wsgi.multiprocess设置为 true,并且始终使用sysos来获取必要的 CGI 流和环境。

此类是SimpleHandler的子类,旨在与 HTTP“起源服务器”以外的软件一起使用。如果您正在编写使用Status:Headers 发送 HTTP 状态的网关协议实现(例如 CGI,FastCGI,SCGI 等),则您可能希望将其子类化,而不是SimpleHandler

此类是BaseHandler的子类。它重写init()get_stdin()get_stderr()add_cgi_vars()_write()_flush()方法,以支持pass构造函数显式设置环境和流。提供的环境和流存储在stdinstdoutstderrenviron属性中。

BaseHandler实例只有一种供外部使用的方法:

在运行应用程序的过程中,所有其他BaseHandler方法都由该方法调用,因此主要存在以允许自定义过程。

在子类中必须重写以下方法:

这里是您可能希望覆盖的其他一些方法和属性。但是,此列表只是一个摘要,并不包括可以覆盖的所有方法。在try创建自定义的BaseHandler子类之前,应查阅文档字符串和源代码以获取其他信息。

定制 WSGI 环境的属性和方法:

定制异常处理的方法和属性:

此方法可以使用sys.exc_info()访问当前错误信息,并在调用它时将其传递给* start_response *(如 PEP 333的“错误处理”部分所述)。

默认实现仅使用error_statuserror_headerserror_body属性来生成输出页面。子类可以覆盖它,以产生更多的动态错误输出。

但是请注意,从安全角度来看,不建议向任何老用户吐出诊断信息。理想情况下,您必须执行一些特殊的操作才能启用诊断输出,这就是默认实现不包含任何内容的原因。

PEP 333的“可选的特定于平台的文件处理”Function的方法和属性:

其他方法和属性:

此属性的默认值在BaseHandler中为 true,但在BaseCGIHandlerCGIHandler中为 false。

20.4.6. Examples

这是一个正在运行的“ Hello World” WSGI 应用程序:

from wsgiref.simple_server import make_server

# 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 (see PEP 333).
def hello_world_app(environ, start_response):
    status = '200 OK'  # HTTP Status
    headers = [('Content-type', 'text/plain')]  # HTTP Headers
    start_response(status, headers)

    # The returned object is going to be printed
    return ["Hello World"]

httpd = make_server('', 8000, hello_world_app)
print "Serving on port 8000..."

# Serve until process is killed
httpd.serve_forever()
首页