标签:
本文只是对PEP3333中关于WSGI的例子的一个简单的记录,方便自己将来查看,若需要详细的信息,请自行查看PEP 3333的官方文档。
WSGI中定义,application端是一个callable term(可以是function,class,method或者是一个实现了__call__方法的实例等),接受两个位置参数(名称不做要求):environ和start_response。
environ是一个标准的python dict对象(不可以是子类),用于保存系统需要的变量。
start_response是一个callable term,接受两个位置参数和一个可选参数,其形式如
start_response(status, response_headers, exc_info=None)
status是一个字符串,形如"200 OK"或者"404 NOT FOUND",状态码和Message以单个空白格分离。
response_headers是一个形如[(header_name, header_value), ...]的列表。
exc_info用于在发生错误时向浏览器输出信息。
start_response必须返回一个形如write(data)的callable,用于向浏览器输出信息。
当application被server调用时,必须返回一个iterable的bytestrings或者是zero(可以使用yield返回一个生成器)。
application端的示例代码如下:
HELLO_WORLD = b"Hello world!\n" def simple_app(environ, start_response): """Simplest possible application object""" status = ‘200 OK‘ response_headers = [(‘Content-type‘, ‘text/plain‘)] start_response(status, response_headers) return [HELLO_WORLD] class AppClass: """Produce the same output, but using a class (Note: ‘AppClass‘ is the "application" here, so calling it returns an instance of ‘AppClass‘, which is then the iterable return value of the "application callable" as required by the spec. If we wanted to use *instances* of ‘AppClass‘ as application objects instead, we would have to implement a ‘__call__‘ method, which would be invoked to execute the application, and we would need to create an instance for use by the server or gateway. """ def __init__(self, environ, start_response): self.environ = environ self.start = start_response def __iter__(self): status = ‘200 OK‘ response_headers = [(‘Content-type‘, ‘text/plain‘)] self.start(status, response_headers) yield HELLO_WORLD
server端的示例代码如下:
import os, sys enc, esc = sys.getfilesystemencoding(), ‘surrogateescape‘ def unicode_to_wsgi(u): # Convert an environment variable to a WSGI "bytes-as-unicode" string return u.encode(enc, esc).decode(‘iso-8859-1‘) def wsgi_to_bytes(s): return s.encode(‘iso-8859-1‘) def run_with_cgi(application): environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()} environ[‘wsgi.input‘] = sys.stdin.buffer environ[‘wsgi.errors‘] = sys.stderr environ[‘wsgi.version‘] = (1, 0) environ[‘wsgi.multithread‘] = False environ[‘wsgi.multiprocess‘] = True environ[‘wsgi.run_once‘] = True if environ.get(‘HTTPS‘, ‘off‘) in (‘on‘, ‘1‘): environ[‘wsgi.url_scheme‘] = ‘https‘ else: environ[‘wsgi.url_scheme‘] = ‘http‘ headers_set = [] headers_sent = [] def write(data): out = sys.stdout.buffer if not headers_set: raise AssertionError("write() before start_response()") elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set out.write(wsgi_to_bytes(‘Status: %s\r\n‘ % status)) for header in response_headers: out.write(wsgi_to_bytes(‘%s: %s\r\n‘ % header)) out.write(wsgi_to_bytes(‘\r\n‘)) out.write(data) out.flush() def start_response(status, response_headers, exc_info=None): if exc_info: try: if headers_sent: # Re-raise original exception if headers sent raise exc_info[1].with_traceback(exc_info[2]) finally: exc_info = None # avoid dangling circular ref elif headers_set: raise AssertionError("Headers already set!") headers_set[:] = [status, response_headers] # Note: error checking on the headers should happen here, # *after* the headers are set. That way, if an error # occurs, start_response can only be re-called with # exc_info set. return write result = application(environ, start_response) try: for data in result: if data: # don‘t send headers until body appears write(data) if not headers_sent: write(‘‘) # send headers now if body was empty finally: if hasattr(result, ‘close‘): result.close()
以上代码均出自PEP 3333官方文档。
标签:
原文地址:http://www.cnblogs.com/chrhust/p/4299880.html