Size: 22685
Comment:
|
Size: 22300
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 7: | Line 7: |
wsgi 是一个 web 组件的接口规范. wsgi将 web 组件分为三类: web服务器,web中间件,web应用程序. 其目标是提高web组件的可重用性. wsgi 的设计目标是适合尽可能广泛的web应用, 较原始. 典型应用: {{{#!python app = A_WSGI_Application(...) app = Middleware1(app, ...) app = Middleware2(app, ...) ... server(app).serve_forever() }}} |
[[Include(AbtWSGI)]] |
简介
相关页面
[http://www.python.org/peps/pep-0333.html Python Web Server Gateway Interface v1.0 PEP333]
[http://pythonpaste.org/ Paste] ["PasteQuickIn"] 为编写基于WSGI的应用程序或框架提供一个良好的基础, 比如:提供wsgi web服务器,常用wsgi中间件 等.
[http://www-128.ibm.com/developerworks/library/wa-wsgi/ Mix and match Web components with Python WSGI]
中译版本 [:/MixMatchWebComponentsWithPyWSGI:使用PyWSGI混合WEB组件]
规范
WSGI应用程序
应用程序对象只是一个接受两个参数的 callable 对象而已. 别把术语 "对象" 误解为真的需要一个实例对象: 一个函数, 方法, 类, 或者实现了 __call__ 方法的实例对象都可以用来作为应用程序对象. 应用程序对象必须能够被重复调用, 因为实际上所有 服务器(除了CGI) 都会发出这样的重复的请求.
The application object is simply a callable object that accepts two arguments. The term "object" should not be misconstrued as requiring an actual object instance: a function, method, class, or instance with a call method are all acceptable for use as an application object. Application objects must be able to be invoked more than once, as virtually all servers/gateways (other than CGI) will make such repeated requests.
(注意: 虽然我们把它说成是一个 "应用程序" 对象, 但也别误解为应用程序开发者会把 WSGI 当一个 web编程API 来用! 我们假定应用程序开发者仍然使用现有的,高层的框架服务来开发他们的应用程序. WSGI 是一个给框架和服务器开发者用的工具, 并且不会提供对应用程序开发者的直接支持.)
(Note: although we refer to it as an "application" object, this should not be construed to mean that application developers will use WSGI as a web programming API! It is assumed that application developers will continue to use existing, high-level framework services to develop their applications. WSGI is a tool for framework and server developers, and is not intended to directly support application developers.)
示例
1 def simple_app(environ, start_response):
2 """Simplest possible application object"""
3 status = '200 OK'
4 response_headers = [('Content-type','text/plain')]
5 start_response(status, response_headers)
6 return ['Hello world!\n']
7
8
9 class AppClass:
10 """Produce the same output, but using a class
11
12 (Note: 'AppClass' is the "application" here, so calling it
13 returns an instance of 'AppClass', which is then the iterable
14 return value of the "application callable" as required by
15 the spec.
16
17 If we wanted to use *instances* of 'AppClass' as application
18 objects instead, we would have to implement a '__call__'
19 method, which would be invoked to execute the application,
20 and we would need to create an instance for use by the
21 server or gateway.
22 """
23
24 def __init__(self, environ, start_response):
25 self.environ = environ
26 self.start = start_response
27
28 def __iter__(self):
29 status = '200 OK'
30 response_headers = [('Content-type','text/plain')]
31 self.start(status, response_headers)
32 yield "Hello world!\n"
WSGI服务器
服务器 或 getway 每次收到 http客户端 发出的请求都会调用一次相应的 应用程序callable . 举例来说, 这里有一个[#head-42263f1a3a5d0f4d19ac223b3f534410d2aaeb62-2 简单的 CGI getway], 以一个接受一个应用程序对象作为参数的函数来实现的. 值得注意的是这个简单的例子还拥有有限的错误处理功能, 因为未捕捉的异常默认会写到 sys.error 里并被web服务器记录下来.
The server or gateway invokes the application callable once for each request it receives from an HTTP client, that is directed at the application. To illustrate, here is a [#head-42263f1a3a5d0f4d19ac223b3f534410d2aaeb62-2 simple CGI gateway], implemented as a function taking an application object. Note that this simple example has limited error handling, because by default an uncaught exception will be dumped to sys.stderr and logged by the web server.
示例
1 import os, sys
2
3 def run_with_cgi(application):
4
5 environ = dict(os.environ.items())
6 environ['wsgi.input'] = sys.stdin
7 environ['wsgi.errors'] = sys.stderr
8 environ['wsgi.version'] = (1,0)
9 environ['wsgi.multithread'] = False
10 environ['wsgi.multiprocess'] = True
11 environ['wsgi.run_once'] = True
12
13 if environ.get('HTTPS','off') in ('on','1'):
14 environ['wsgi.url_scheme'] = 'https'
15 else:
16 environ['wsgi.url_scheme'] = 'http'
17
18 headers_set = []
19 headers_sent = []
20
21 def write(data):
22 if not headers_set:
23 raise AssertionError("write() before start_response()")
24
25 elif not headers_sent:
26 # Before the first output, send the stored headers
27 status, response_headers = headers_sent[:] = headers_set
28 sys.stdout.write('Status: %s\r\n' % status)
29 for header in response_headers:
30 sys.stdout.write('%s: %s\r\n' % header)
31 sys.stdout.write('\r\n')
32
33 sys.stdout.write(data)
34 sys.stdout.flush()
35
36 def start_response(status,response_headers,exc_info=None):
37 if exc_info:
38 try:
39 if headers_sent:
40 # Re-raise original exception if headers sent
41 raise exc_info[0], exc_info[1], exc_info[2]
42 finally:
43 exc_info = None # avoid dangling circular ref
44 elif headers_set:
45 raise AssertionError("Headers already set!")
46
47 headers_set[:] = [status,response_headers]
48 return write
49
50 result = application(environ, start_response)
51 try:
52 for data in result:
53 if data: # don't send headers until body appears
54 write(data)
55 if not headers_sent:
56 write('') # send headers now if body was empty
57 finally:
58 if hasattr(result,'close'):
59 result.close()
WSGI中间件
注意一个对象可以在一些应用程序面前是服务器, 而从一些服务器看来却是应用程序. 这样的 "中间件" 可以实现以下一些功能:
Note that a single object may play the role of a server with respect to some application(s), while also acting as an application with respect to some server(s). Such "middleware" components can perform such functions as:
可以根据目的 URL 将一个请求分发 (routing) 给不同的应用程序对象, 并对 environ 做相应修改.
- Routing a request to different application objects based on the
target URL, after rewriting the environ accordingly.
- 允许多个应用程序或框架在同一个进程中一起运行.
- Allowing multiple applications or frameworks to run side-by-side
- in the same process
- 通过在网络上转发请求和响应, 进行负载均衡和远程处理.
- Load balancing and remote processing, by forwarding requests and
- responses over a network
- 对内容进行后加工, 比如应用 XSL 样式.
- Perform content postprocessing, such as applying XSL stylesheets
通常中间件的存在对 服务器 和 应用程序 两边的接口都是透明的, 并且应该不需要提供什么特殊的支持. 用户如果想在应用程序中组合一个中间件, 只需简单地把中间件当个应用程序提供给服务器, 并配置该中间件, 让它以服务器的身份来调用应用程序. 当然中间件包装的这个应用程序实际上可能是一个包装着另一个应用程序的中间件, 如此反复, (以至无穷), 最终形成了传说中的 "中间件栈" .
The presence of middleware in general is transparent to both the "server/gateway" and the "application/framework" sides of the interface, and should require no special support. A user who desires to incorporate middleware into an application simply provides the middleware component to the server, as if it were an application, and configures the middleware component to invoke the application, as if the middleware component were a server. Of course, the "application" that the middleware wraps may in fact be another middleware component wrapping another application, and so on, creating what is referred to as a "middleware stack".
在多数情况下, 中间件必须同时遵守WSGI服务器和WSGI应用程序两边的限制和需要. 而且在某些情况下, 对中间件的要求比一个纯粹服务器或应用程序还要严格, 这几个方面在规范中还会涉及到.
For the most part, middleware must conform to the restrictions and requirements of both the server and application sides of WSGI. In some cases, however, requirements for middleware are more stringent than for a "pure" server or application, and these points will be noted in the specification.
这里有一个 (随手写的) 中间件的例子, 它将 text/plain 的响应转换成 pig latin, 用到 Joe Strout 的 piglatin.py. (注意: 一个 "真实" 的中间件组件很可能会使用一种更成熟的方式来检查 content type, 而且还应该检查一下 content encoding. 另外, 这个简单的例子还忽略了一个单词可能会在数据块的边界处被分割.)
Here is a (tongue-in-cheek) example of a middleware component that converts text/plain responses to pig latin, using Joe Strout's piglatin.py. (Note: a "real" middleware component would probably use a more robust way of checking the content type, and should also check for a content encoding. Also, this simple example ignores the possibility that a word might be split across a block boundary.)
示例
1 from piglatin import piglatin
2
3 class LatinIter:
4
5 """Transform iterated output to piglatin, if it's okay to do so
6
7 Note that the "okayness" can change until the application yields
8 its first non-empty string, so 'transform_ok' has to be a mutable
9 truth value."""
10
11 def __init__(self,result,transform_ok):
12 if hasattr(result,'close'):
13 self.close = result.close
14 self._next = iter(result).next
15 self.transform_ok = transform_ok
16
17 def __iter__(self):
18 return self
19
20 def next(self):
21 if self.transform_ok:
22 return piglatin(self._next())
23 else:
24 return self._next()
25
26 class Latinator:
27
28 # by default, don't transform output
29 transform = False
30
31 def __init__(self, application):
32 self.application = application
33
34 def __call__(self, environ, start_response):
35
36 transform_ok = []
37
38 def start_latin(status,response_headers,exc_info=None):
39
40 # Reset ok flag, in case this is a repeat call
41 transform_ok[:]=[]
42
43 for name,value in response_headers:
44 if name.lower()=='content-type' and value=='text/plain':
45 transform_ok.append(True)
46 # Strip content-length if present, else it'll be wrong
47 response_headers = [(name,value)
48 for name,value in response_headers
49 if name.lower()<>'content-length'
50 ]
51 break
52
53 write = start_response(status,response_headers,exc_info)
54
55 if transform_ok:
56 def write_latin(data):
57 write(piglatin(data))
58 return write_latin
59 else:
60 return write
61
62 return LatinIter(self.application(environ,start_latin),transform_ok)
63
64
65 # Run foo_app under a Latinator's control, using the example CGI gateway
66 from foo_app import foo_app
67 run_with_cgi(Latinator(foo_app))
规范细节
应用程序对象必须接受两个固定参数,为了方便说明我们不妨把他们命名为 environ 和 start_response ,但并非必须取这个名字。服务器或gateway必须使用这两个参数来调用应用程序对象 ( 就象上面展示的那样, 像这样调用 result = application(environ,start_response) )
The application object must accept two positional arguments. For the sake of illustration, we have named them environ and start_response, but they are not required to have these names. A server or gateway must invoke the application object using positional (not keyword) arguments. (E.g. by calling result = application(environ,start_response) as shown above.)
environ 参数是个字典,其中包含的是 CGI 风格的环境变量。这个对象必须是一个 python 内置的字典对象 (不能是其子类、UserDict或其他对字典对象的模仿) ,应用程序可以任意修改这个字典, environ 还应该包含一些 WSGI 需要的特定变量 (在后面的节里还会描述) ,还可以包含一些依据一定的命名规范的服务器特定的扩展变量, 命名规范在后面还会有描述。
The environ parameter is a dictionary object, containing CGI-style environment variables. This object must be a builtin Python dictionary (not a subclass, UserDict or other dictionary emulation), and the application is allowed to modify the dictionary in any way it desires. The dictionary must also include certain WSGI-required variables (described in a later section), and may also include server-specific extension variables, named according to a convention that will be described below.
参数 start_response 是一个接受两个必需的固定参数和一个可选参数的 callable 对象. 为便于说明, 我们把这三个参数分别命名为: status, response_headers, 和 exc_info, 当然你也可以给他们起其他名字. 应用程序必需使用固定参数调用 start_response (比如: start_response(status,response_headers))
The start_response parameter is a callable accepting two required positional arguments, and one optional argument. For the sake of illustration, we have named these arguments status, response_headers, and exc_info, but they are not required to have these names, and the application must invoke the start_response callable using positional arguments (e.g. start_response(status,response_headers)).
参数 status 是一个形如 "999 Message here" 的表示状态的字符串。而 response_headers 参数是一个描述 http 响应头的列表, 其中每一个元素都是像 (header_name,header_value) 这样的元组。可选的 exc_info 参数会在后面的 start_response() callable 和 错误处理 两节中进行描述,该参数只有在应用程序产生了错误并希望在浏览器上显示错误信息的时候才用得上。
The status parameter is a status string of the form "999 Message here", and response_headers is a list of (header_name,header_value) tuples describing the HTTP response header. The optional exc_info parameter is described below in the sections on The start_response() Callable and Error Handling. It is used only when the application has trapped an error and is attempting to display an error message to the browser.
start_response callable 必须返回一个 write(body_data) callable,该 callable 接受一个可选参数:一个将会被作为 http body 一部分输出的字符串. (注意:提供 write() callable 只是为了支持几个现有框架急需的输出API,新的应用程序或框架应尽量避免使用,详细情况请看 Buffering and Streaming 一节。)
The start_response callable must return a write(body_data) callable that takes one positional parameter: a string to be written as part of the HTTP response body. (Note: the write() callable is provided only to support certain existing frameworks' imperative output APIs; it should not be used by new applications or frameworks if it can be avoided. See the Buffering and Streaming section for more details.)
当被服务器调用的时候, 应用程序对象必须返回一个能产生零或多个字符串的 iterable , 这可以有好几种实现方法, 比如返回一个字符串的列表,或者应用程序本身就是一个产生字符串的生成器, 或者应用程序本身是一个类 而他的实例是 iterable . 不管它是怎么实现,应用程序对象总是必须返回一个能产生零或多个字符串的 iterable 。
When called by the server, the application object must return an iterable yielding zero or more strings. This can be accomplished in a variety of ways, such as by returning a list of strings, or by the application being a generator function that yields strings, or by the application being a class whose instances are iterable. Regardless of how it is accomplished, the application object must always return an iterable yielding zero or more strings.
服务器必须将产生的字符串以一种无缓冲的方式传输到客户端,每次传输完一个字符串再去获取下一个。(换句话说,应用程序应该自己实现缓冲,更多关于应用程序输出必须如何处理的细节请阅读后面的 Buffering and Streaming_ 节。)
The server or gateway must transmit the yielded strings to the client in an unbuffered fashion, completing the transmission of each string before requesting another one. (In other words, applications should perform their own buffering. See the Buffering and Streaming section below for more on how application output must be handled.)
服务器或gateway应该把应用程序产生的字符串当字节流对待:特别地,他必须保证行尾是未修改过的。应用程序负责保证输出的这些字符串的编码是与客户端匹配的 ( 服务器/gateway 可能会附加 HTTP 传送编码,或者为了实现一些http的特性而对内容进行其他的转换比如 byte-range transmission , 更多这方面的细节请看后面的 Other HTTP Features )
The server or gateway should treat the yielded strings as binary byte sequences: in particular, it should ensure that line endings are not altered. The application is responsible for ensuring that the string(s) to be written are in a format suitable for the client. (The server or gateway may apply HTTP transfer encodings, or perform other transformations for the purpose of implementing HTTP features such as byte-range transmission. See Other HTTP Features, below, for more details.)
如果调用 len(iterable) 成功的话, 服务器便会假定返回的结果是正确的。也就是说, 只要应用程序返回的 iterable 提供了有效的 __len__() 方法,就可以肯定它返回的结果是正确的. (关于通常情况下这个方法应该如何使用的问题请阅读 Handling the Content-Length Header 一节 )
If a call to len(iterable) succeeds, the server must be able to rely on the result being accurate. That is, if the iterable returned by the application provides a working len() method, it must return an accurate result. (See the Handling the Content-Length Header section for information on how this would normally be used.)
如果应用程序返回的 iterable 拥有 close() 方法, 则不管该请求是正常结束的还是由于出错而终止的, 服务器/gateway 都 *必须* 在结束该请求之前调用这个方法,(这是用来支持应用程序对资源的释放的, 这个协议是特别用来提供对 PEP 325 的生成器 和 其他带有 close() 方法的 iterable 的支持 )
If the iterable returned by the application has a close() method, the server or gateway must call that method upon completion of the current request, whether the request was completed normally, or terminated early due to an error. (This is to support resource release by the application. This protocol is intended to complement PEP 325's generator support, and other common iterables with close() methods.
(注意:应用程序必须在 iterable 产生第一个 body 字符串之间调用 start_response() callable, 这样服务器才能在发送任何 body 内容之前发送 response header, 不过这个步骤也可以在 iterable 执行第一次迭代的时候执行,所以服务器不能假定在开始迭代之前 start_response() 一定被调用过了)
(Note: the application must invoke the start_response() callable before the iterable yields its first body string, so that the server can send the headers before any body content. However, this invocation may be performed by the iterable's first iteration, so servers must not assume that start_response() has been called before they begin iterating over the iterable.)
最后, 服务器和gateway 绝不能直接使用应用程序返回的 iterable 的任何其他的属性, 除非是针对该 服务器或gateway 特定的情形, 比如 wsgi.file_wrapper 返回的 file wrapper (阅读 Optional Platform-Specific File Handling)。通常, 只能访问这里指定的属性, 或者也可以通过 PEP 234 iteration APIs 进行访问。
Finally, servers and gateways must not directly use any other attributes of the iterable returned by the application, unless it is an instance of a type specific to that server or gateway, such as a "file wrapper" returned by wsgi.file_wrapper (see Optional Platform-Specific File Handling). In the general case, only attributes specified here, or accessed via e.g. the PEP 234 iteration APIs are acceptable.
environ 变量
start_response() callable
Buffering and Streaming