wsgiref
——wsgi实用程序和参考实现¶
Web服务器网关接口(wsgi)是Web服务器软件和用python编写的Web应用程序之间的标准接口。有了一个标准的接口,就可以很容易地使用一个支持wsgi的应用程序和许多不同的Web服务器。
只有Web服务器和编程框架的作者才需要了解WSGi设计的每个细节和关键案例。您不需要仅仅为了安装一个WSGi应用程序或使用现有框架编写一个Web应用程序而理解WSGi的每一个细节。
wsgiref
是wsgi规范的引用实现,可用于向Web服务器或框架添加wsgi支持。它提供了操作wsgi环境变量和响应头的实用程序、实现wsgi服务器的基类、为wsgi应用程序提供服务的演示HTTP服务器以及检查wsgi服务器和应用程序是否符合wsgi规范的验证工具。 (PEP 3333 )
见 wsgi.readthedocs.io 有关wsgi的更多信息,以及到教程和其他资源的链接。
wsgiref.util
--WSGi环境实用程序¶
此模块提供了各种用于使用WSGi环境的实用程序功能。wsgi环境是一个包含HTTP请求变量的字典,如中所述。 PEP 3333 . 所有的函数 环境 参数要求提供符合wsgi的字典;请参阅 PEP 3333 详细规格。
- wsgiref.util.guess_scheme(environ)¶
对是否
wsgi.url_scheme
应该是“http”或“https”,通过检查HTTPS
中的环境变量 环境 字典。返回值是一个字符串。当创建一个包含CGI或类似CGI的协议(如FastCGI)的网关时,此函数非常有用。通常,提供此类协议的服务器将包括
HTTPS
通过SSL接收请求时,值为“1”、“是”或“开”的变量。因此,如果找到这样的值,这个函数将返回“https”,否则返回“http”。
- wsgiref.util.request_uri(environ, include_query=True)¶
使用“URL重建”部分中的算法返回完整的请求URI(可选包括查询字符串)。 PEP 3333 . 如果 include_query 为false,查询字符串不包含在生成的URI中。
- wsgiref.util.application_uri(environ)¶
类似
request_uri()
除了PATH_INFO
和QUERY_STRING
变量被忽略。结果是请求所寻址的应用程序对象的基URI。
- wsgiref.util.shift_path_info(environ)¶
将单个名称从
PATH_INFO
到SCRIPT_NAME
并返回名称。这个 环境 字典是 被改进的 到位;如果需要保留原件,请使用副本PATH_INFO
或SCRIPT_NAME
完整的。如果中没有剩余的路径段
PATH_INFO
,None
返回。通常,此例程用于处理请求URI路径的每个部分,例如将路径视为一系列字典键。此例程修改传入的环境,使其适合调用位于目标URI上的另一个WSGi应用程序。例如,如果在
/foo
,请求的URI路径为/foo/bar/baz
和wsgi应用程序/foo
调用shift_path_info()
,它将接收字符串“bar”,并且将更新环境以适合传递到位于的wsgi应用程序/foo/bar
. 也就是说,SCRIPT_NAME
将从更改/foo
到/foo/bar
和PATH_INFO
将从更改/bar/baz
到/baz
.什么时候?
PATH_INFO
只是一个“/”,此例程返回一个空字符串,并将尾随斜杠追加到SCRIPT_NAME
,即使通常忽略空路径段,并且SCRIPT_NAME
通常不会以斜线结尾。这是有意的行为,以确保应用程序能够区分以/x
从最后一个/x/
使用此例程进行对象遍历时。
- wsgiref.util.setup_testing_defaults(environ)¶
更新 环境 为了测试的目的,使用一些简单的默认值。
这个例程添加了wsgi所需的各种参数,包括
HTTP_HOST
,SERVER_NAME
,SERVER_PORT
,REQUEST_METHOD
,SCRIPT_NAME
,PATH_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)¶
返回
True
如果“header_name”是HTTP/1.1“Hop-by-Hop”头,则由 RFC 2616 .
- class wsgiref.util.FileWrapper(filelike, blksize=8192)¶
将类似文件的对象转换为 iterator . 结果对象同时支持
__getitem__()
和__iter__()
迭代样式,与Python2.1和Jython兼容。当对象被迭代时,可选的 chunksize 参数将重复传递到 类丝状的 对象的read()
方法获取要生成的字节数。什么时候?read()
返回空的bytestring,迭代结束,不可恢复。如果 类丝状的 有一个
close()
方法,返回的对象还将具有close()
方法,它将调用 类丝状的 对象的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.8 版后已移除: 支持
sequence protocol
被贬低。
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()
如果存在多值头,则可以多次包含同一个键。这个len()
A的Headers
对象的长度与其items()
,与换行标题列表的长度相同。事实上,items()
方法只返回封装头列表的副本。调用
bytes()
在一Headers
对象返回适合作为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应用程序提供服务。如果要在单个主机和端口上为多个应用程序提供服务,则应创建一个分析 PATH_INFO
为每个请求选择要调用的应用程序。(例如,使用 shift_path_info()
函数来自 wsgiref.util
)
- wsgiref.simple_server.make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler)¶
创建新的WSGi服务器侦听 host 和 port ,接受的连接 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!”的文本页。以及在 环境 参数。它对于验证wsgi服务器(例如
wsgiref.simple_server
)能够正确运行一个简单的wsgi应用程序。
- class wsgiref.simple_server.WSGIServer(server_address, RequestHandlerClass)¶
创建一个
WSGIServer
实例。 server_address 应该是(host,port)
元组,以及 RequestHandlerClass 应该是的子类http.server.BaseHTTPRequestHandler
将用于处理请求。通常不需要调用此构造函数,因为
make_server()
函数可以为您处理所有细节。WSGIServer
是的子类http.server.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)¶
为给定的创建HTTP处理程序 请求 (即Socket) client_address (A)
(host,port)
元组) 服务器 (WSGIServer
实例)。您不需要直接创建这个类的实例;它们是根据需要自动创建的
WSGIServer
物体。但是,您可以将该类划分为子类,并将其作为 handler_class 到make_server()
功能。在子类中重写的一些可能相关的方法:- get_environ()¶
返回包含请求的wsgi环境的字典。默认实现复制
WSGIServer
对象的base_environ
Dictionary属性,然后添加从HTTP请求派生的各种头。对该方法的每次调用都应返回一个新字典,其中包含在中指定的所有相关CGI环境变量。 PEP 3333 .
- get_stderr()¶
返回应用作
wsgi.errors
溪流。默认实现只返回sys.stderr
.
- handle()¶
处理HTTP请求。默认实现使用
wsgiref.handlers
类来实现实际的wsgi应用程序接口。
wsgiref.validate
---WSGI一致性检查器¶
在创建新的WSGi应用程序对象、框架、服务器或中间件时,使用 wsgiref.validate
. 此模块提供了一个创建WSGi应用程序对象的函数,用于验证WSGi服务器或网关与WSGi应用程序对象之间的通信,以检查双方的协议一致性。
请注意,此实用程序不能保证完成 PEP 3333 合规性;此模块中没有错误并不一定意味着不存在错误。但是,如果这个模块确实产生了错误,那么实际上可以确定服务器或应用程序不是100%兼容的。
此模块基于 paste.lint
来自IanBicking的“python-paste”库的模块。
- wsgiref.validate.validator(application)¶
包裹 应用 并返回一个新的wsgi应用程序对象。返回的应用程序将所有请求转发到原始 应用 并将检查 应用 调用它的服务器符合wsgi规范,并且 RFC 2616 .
任何检测到的不合格都会导致
AssertionError
但是,请注意,如何处理这些错误取决于服务器。例如,wsgiref.simple_server
以及其他基于wsgiref.handlers
(不重写错误处理方法以执行其他操作的方法)只会输出已发生错误的消息,并将跟踪转储到sys.stderr
或其他错误流。这个封装器还可以使用
warnings
用于指示有问题但实际上可能未被禁止的行为的模块 PEP 3333 . 除非使用python命令行选项或warnings
API,任何此类警告都将写入sys.stderr
( notwsgi.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¶
基于CGI的调用通过
sys.stdin
,sys.stdout
,sys.stderr
和os.environ
. 当您有一个wsgi应用程序并希望以CGI脚本的形式运行它时,这很有用。简单调用CGIHandler().run(app)
在哪里app
是要调用的WSGi应用程序对象。这个类是
BaseCGIHandler
那套wsgi.run_once
说真的,wsgi.multithread
假的,以及wsgi.multiprocess
为真,并始终使用sys
和os
获取必要的CGI流和环境。
- class wsgiref.handlers.IISCGIHandler¶
专业的替代品
CGIHandler
,用于在Microsoft的IIS Web服务器上部署时,而不设置config allowpathinfo选项(IIS>=7)或元数据库allowpathinfoforscriptmappings(IIS<7)。默认情况下,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
但不是使用sys
和os
明确指定模块、CGI环境和I/O流。这个 多线程 和 多进程 值用于设置wsgi.multithread
和wsgi.multiprocess
由处理程序实例运行的任何应用程序的标志。这个类是
SimpleHandler
用于HTTP“源服务器”以外的软件。如果您正在编写使用Status:
要发送HTTP状态,您可能需要将其子类化,而不是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()
方法来支持通过构造函数显式设置环境和流。提供的环境和流存储在stdin
,stdout
,stderr
和environ
属性。这个
write()
方法 stdout 应该完整地编写每个块,比如io.BufferedIOBase
.
- class wsgiref.handlers.BaseHandler¶
这是用于运行wsgi应用程序的抽象基类。每个实例都将处理一个HTTP请求,尽管原则上您可以创建一个可用于多个请求的子类。
BaseHandler
实例只有一个用于外部使用的方法:- run(app)¶
运行指定的wsgi应用程序, app .
所有其他的
BaseHandler
方法在运行应用程序的过程中被此方法调用,因此主要存在于允许自定义过程的情况下。必须在子类中重写以下方法:
- _write(data)¶
缓冲字节 data 用于传输给客户。如果这个方法真的传输数据是可以的;
BaseHandler
当底层系统实际上有这样的区别时,只需将写操作和刷新操作分开,以提高效率。
- get_stdin()¶
返回适合用作
wsgi.input
当前正在处理的请求。
- get_stderr()¶
返回适合用作
wsgi.errors
当前正在处理的请求。
- add_cgi_vars()¶
将当前请求的CGI变量插入
environ
属性。
下面是一些您可能希望重写的其他方法和属性。然而,这个列表只是一个摘要,不包括所有可以重写的方法。在尝试创建自定义的
BaseHandler
子类。自定义wsgi环境的属性和方法:
- wsgi_multithread¶
要用于的值
wsgi.multithread
环境变量。它默认为true inBaseHandler
,但在其他子类中可能有不同的默认值(或由构造函数设置)。
- wsgi_multiprocess¶
要用于的值
wsgi.multiprocess
环境变量。它默认为true inBaseHandler
,但在其他子类中可能有不同的默认值(或由构造函数设置)。
- wsgi_run_once¶
要用于的值
wsgi.run_once
环境变量。在BaseHandler
,但是CGIHandler
默认情况下将其设置为true。
- os_environ¶
每个请求的wsgi环境中要包含的默认环境变量。默认情况下,这是
os.environ
在那个时候wsgiref.handlers
已导入,但子类可以在类或实例级别创建自己的子类。注意,字典应该被认为是只读的,因为默认值在多个类和实例之间共享。
- server_software¶
如果
origin_server
属性已设置,此属性的值用于设置默认值SERVER_SOFTWARE
wsgi环境变量,以及设置默认值Server:
HTTP响应中的头。对于处理程序(例如BaseCGIHandler
和CGIHandler
)不是HTTP源服务器。在 3.3 版更改: 术语“python”替换为特定于实现的术语,如“cpython”、“jython”等。
- get_scheme()¶
返回当前请求使用的URL方案。默认实现使用
guess_scheme()
函数来自wsgiref.util
根据当前请求的environ
变量。
- 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.exc_info()
,并应将该信息传递给 start_response 调用它时(如“错误处理”部分所述 PEP 3333 )默认实现只使用
error_status
,error_headers
和error_body
用于生成输出页的属性。子类可以重写此项以生成更动态的错误输出。但是,请注意,从安全角度来看,不建议向任何旧用户发出诊断;理想情况下,您应该做一些特殊的事情来启用诊断输出,这就是默认实现不包含任何诊断输出的原因。
- error_headers¶
用于错误响应的HTTP头。这应该是wsgi响应头的列表 (
(name, value)
元组),如中所述 PEP 3333 . 默认列表只将内容类型设置为text/plain
.
- error_body¶
错误响应正文。这应该是一个HTTP响应主体bytestring。它默认为纯文本,“发生服务器错误。请联系管理员。“
的方法和属性 PEP 3333 “S”可选平台特定文件处理“功能:
- wsgi_file_wrapper¶
A
wsgi.file_wrapper
工厂,或None
. 此属性的默认值是wsgiref.util.FileWrapper
类。
- sendfile()¶
覆盖以实现平台特定的文件传输。仅当应用程序的返回值是由
wsgi_file_wrapper
属性。如果能够成功传输文件,它应该返回一个真值,这样默认的传输代码就不会被执行。此方法的默认实现只返回一个错误值。
其他方法和属性:
- origin_server¶
如果处理程序的
_write()
和_flush()
正被用来直接与客户机通信,而不是通过一个类似CGI的网关协议,该协议希望在一个特殊的Status:
标题。此属性的默认值在中为真
BaseHandler
但在BaseCGIHandler
和CGIHandler
.
- http_version¶
如果
origin_server
为true,此字符串属性用于将响应集的HTTP版本设置为客户端。它默认为"1.0"
.
- wsgiref.handlers.read_environ()¶
将CGI变量从
os.environ
到 PEP 3333 “bytes in unicode”字符串,返回新字典。此函数由使用CGIHandler
和IISCGIHandler
代替直接使用os.environ
在所有使用python 3的平台和Web服务器上,这不一定符合wsgi——特别是操作系统的实际环境是unicode(即windows)的平台和Web服务器,或者环境是字节的平台和Web服务器,但python用于解码的系统编码与iso-8859-1(如使用utf-8的Unix系统)不同。如果您正在实现自己的基于CGI的处理程序,那么您可能希望使用此例程,而不只是从
os.environ
直接。3.2 新版功能.
实例¶
这是一个正常工作的“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.
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):
#!/usr/bin/env python3
'''
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. Used for the make serve target in Doc.
'''
import sys
import os
import mimetypes
from wsgiref import simple_server, util
def app(environ, respond):
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')
type = mimetypes.guess_type(fn)[0]
if os.path.exists(fn):
respond('200 OK', [('Content-Type', type)])
return util.FileWrapper(open(fn, "rb"))
else:
respond('404 Not Found', [('Content-Type', 'text/plain')])
return [b'not found']
if __name__ == '__main__':
path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
port = int(sys.argv[2]) if len(sys.argv) > 2 else 8000
httpd = simple_server.make_server('', port, app)
print("Serving {} on port {}, control-C to stop".format(path, port))
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("Shutting down.")
httpd.server_close()