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了解详细说明。

  • wsgiref.util. guess_scheme(环境)
    • pass检查* environ *词典中的HTTPS环境变量,返回关于wsgi.url_scheme是“ http”还是“ https”的猜测。返回值是一个字符串。

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

  • wsgiref.util. request_uri(* environ include_query = 1 *)

    • 使用 PEP 333的“ URL 重构”部分中找到的算法,返回完整的请求 URI(可选地包括查询字符串)。如果* include_query *为 false,则查询字符串不包含在结果 URI 中。
  • wsgiref.util. application_uri(环境)

    • request_uri()相似,但忽略PATH_INFOQUERY_STRING变量。结果是请求所寻址的应用程序对象的基本 URI。
  • wsgiref.util. shift_path_info(环境)

    • 将单个名称从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 *。

此例程添加了 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:

  • wsgiref.util. is_hop_by_hop(* header_name *)

    • 如果'header_name'是 HTTP_1.1 RFC 2616定义的“逐跳”Headers,则返回 true。
    • class * wsgiref.util. FileWrapper(* filelike blksize = 8192 *)
    • 包装器,用于将类似文件的对象转换为iterator。生成的对象支持getitem()iter()迭代样式,以与 Python 2.1 和 Jython 兼容。随着对象的迭代,可选的* blksize 参数将反复传递给 filelike *对象的read()方法,以获取要产生的字符串。 read()返回空字符串时,迭代结束且不可恢复。

如果* 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。

    • class * wsgiref.headers. Headers(* headers *)
    • 创建一个包装* headers 的类似 Map 的对象,该对象必须是 PEP 333中描述的标题名称/值 Tuples 的列表。对新的Headers对象所做的任何更改都会直接更新其创建时使用的 header *列表。

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:

  • get_all(* name *)
    • 返回命名 Headers 的所有值的列表。

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

  • add_header((* name value ** _ params *)
    • 添加一个(可能是多值的)标题,并pass关键字参数指定可选的 MIME 参数。
  • name *是要添加的标题字段。关键字参数可用于设置 Headers 字段的 MIME 参数。每个参数必须是字符串或None。参数名称中的下划线将转换为破折号,因为破折号在 Python 标识符中是非法的,但是许多 MIME 参数名称都包含破折号。如果参数值是字符串,则以name="value"的形式将其添加到 Headers 值参数中。如果为None,则仅添加参数名称。 (这用于没有值的 MIME 参数.)用法示例:
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()函数。)

  • wsgiref.simple_server. make_server(* host port app server_class = WSGIServer handler_class = WSGIRequestHandler *)
    • 创建一个新的 WSGI 服务器,监听* host port ,接受 app 的连接。返回值是提供的 server_class 的实例,并将使用指定的 handler_class *处理请求。 * app *必须是 PEP 333定义的 WSGI 应用程序对象。

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

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

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

  • set_app(应用程序)

    • 将可调用的* application *设置为将接收请求的 WSGI 应用程序。
  • get_app ( )

    • 返回当前设置的可调用应用程序。

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

    • class * wsgiref.simple_server. WSGIRequestHandler(* request client_address server *)
    • 为给定的* request (即套接字), client_address ((host,port)Tuples)和 server *(WSGIServer实例)创建 HTTP 处理程序。

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

  • get_environ ( )

    • 返回包含请求的 WSGI 环境的字典。默认实现将复制WSGIServer对象的base_environ字典属性的内容,然后添加从 HTTP 请求派生的各种 Headers。每次对此方法的调用都应返回一个新字典,其中包含 PEP 333中指定的所有相关 CGI 环境变量。
  • get_stderr ( )

    • 返回应用作wsgi.errors流的对象。默认实现只是返回sys.stderr
  • handle ( )

    • 处理 HTTP 请求。缺省实现使用wsgiref.handlers类创建一个处理程序实例,以实现实际的 WSGI 应用程序接口。

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

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

请注意,该 Util 不能保证完全符合 PEP 333的要求;该模块中没有错误并不一定意味着不存在错误。但是,如果此模块确实产生错误,则实际上可以确定服务器或应用程序不是 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 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,输出和错误流即可。

  • 类别 wsgiref.handlers. CGIHandler
    • passsys.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. BaseCGIHandler(* stdin stdout stderr environ multithread = True multiprocess = False *)
    • CGIHandler相似,但是不使用sysos模块,而是显式指定 CGI 环境和 I/O 流。 * multithread multiprocess *值用于为处理程序实例运行的任何应用程序设置wsgi.multithreadwsgi.multiprocess标志。

此类是SimpleHandler的子类,旨在与 HTTP“起源服务器”以外的软件一起使用。如果您正在编写使用Status:Headers 发送 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()方法,以支持pass构造函数显式设置环境和流。提供的环境和流存储在stdinstdoutstderrenviron属性中。

  • 类别 wsgiref.handlers. BaseHandler
    • 这是用于运行 WSGI 应用程序的抽象 Base Class。每个实例将处理一个 HTTP 请求,尽管原则上您可以创建可用于多个请求的子类。

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

  • run(* app *)
    • 运行指定的 WSGI 应用程序* app *。

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

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

  • _write(* data *)

    • 缓冲字符串* data *以便传输到 Client 端。如果该方法实际传输数据也可以;当基础系统实际上具有这种区别时,BaseHandler只是将写操作和刷新操作分开以提高效率。
  • _flush ( )

    • 强制将缓冲的数据传输到 Client 端。此方法为空操作也可以(例如_write()实际发送数据)。
  • get_stdin ( )

    • 返回适合用作当前正在处理的请求的wsgi.input的 Importing 流对象。
  • get_stderr ( )

    • 返回适合用作当前正在处理的请求的wsgi.errors的输出流对象。
  • add_cgi_vars ( )

    • 将当前请求的 CGI 变量插入environ属性。

这里是您可能希望覆盖的其他一些方法和属性。但是,此列表只是一个摘要,并不包括可以覆盖的所有方法。在try创建自定义的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:Headers。对于不是 HTTP 源服务器的处理程序(例如BaseCGIHandlerCGIHandler),将忽略它。
  • get_scheme ( )

    • 返回用于当前请求的 URL 方案。默认实现使用来自wsgiref.utilguess_scheme()函数根据当前请求的environ变量猜测方案是“ http”还是“ https”。
  • setup_environ ( )

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

  • log_exception(* exc_info *)

    • 在服务器日志中记录* exc_info *Tuples。 * exc_info *是(type, value, traceback)Tuples。默认实现只是将回溯写到请求的wsgi.errors流中并将其刷新。子类可以重写此方法,以更改格式或重新定位输出,将 traceback 邮件发送给 Management 员或采取其他任何认为合适的措施。
  • traceback_limit

    • 默认log_exception()方法输出的回溯中要包括的最大帧数。如果None,则包括所有帧。
  • error_output((* environ start_response *)

    • 此方法是 WSGI 应用程序,用于为用户生成错误页面。仅在将头发送到 Client 端之前发生错误时才调用它。

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

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

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

  • error_status

    • 用于错误响应的 HTTP 状态。这应该是 PEP 333中定义的状态字符串;它默认为 500 个代码和消息。
  • error_headers

    • 用于错误响应的 HTTPHeaders。如 PEP 333所述,这应该是 WSGI 响应头((name, value)Tuples)的列表。默认列表仅将 Content Type 设置为text/plain
  • error_body

    • 错误响应主体。这应该是 HTTP 响应正 Literals 符串。默认为纯文本,“发生服务器错误。请与 Management 员联系。”

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

  • wsgi_file_wrapper

    • wsgi.file_wrapper工厂或None。此属性的默认值为wsgiref.utilFileWrapper类。
  • sendfile ( )

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

其他方法和属性:

  • origin_server
    • 如果使用处理程序的_write()_flush()直接与 Client 端通信,而不是pass希望在特殊Status:Headers 中使用 HTTP 状态的类似于 CGI 的网关协议,则应将此属性设置为 true 值。

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

  • http_version
    • 如果origin_server为 true,则此字符串属性用于将响应集的 HTTP 版本设置为 Client 端。默认为"1.0"

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