Differences between revisions 1 and 5 (spanning 4 versions)
Revision 1 as of 2006-02-03 11:58:04
Size: 773
Editor: hoxide
Comment:
Revision 5 as of 2006-08-23 02:52:32
Size: 10873
Editor: HuangYi
Comment:
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
'''
含有章节缩影的FLOSS中文 文章模板
'''::-- hoxide [[[DateTime(2006-02-03T11:58:04Z)]]]
Line 7: Line 5:
== WSGI ==
 Python Web Server Gateway Interface (WSGI) 是一个Python的Web服务器接口, 它的目标是为web framework提供与http server之间的接口, 让web framework可以运行再不同的http server之上, WSGI属于中间件. Guido近期的Blog中对WSGI的评价非常高.

=== 简介 ===


=== 官方页面 ===
 WSGI没有官方实现, 他更类似于一个协议, 参看:
[http://www.python.org/peps/pep-0333.html#middleware-components-that-play-both-sides Python Web Server Gateway Interface v1.0 PEP333]

=== 文档 ==

=== 例子 ===

=== 讨论 ===

== 简介 ==

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

== 相关页面 ==

 * [http://www.python.org/peps/pep-0333.html Python Web Server Gateway Interface v1.0 PEP333]
 * http://wsgi.org/
 * [http://pythonpaste.org/ Paste] ["PasteQuickIn"] 为编写基于WSGI的应用程序或框架提供一个良好的基础, 比如:提供wsgi web服务器,常用wsgi中间件 等.
== 规范 ==
=== WSGI应用程序 ===
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.

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

[#head-719d788ab1dd4f4bb61a26f59256d3a0dfc66cde-2 示例]
=== WSGI服务器 ===
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 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.

[#head-747ebe56750a1de964d165b5b4a56e9eeb2f74a4-2 示例]
=== 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.

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

[#head-229f9e55e6acb5e474a68f7293b978f55ff3beb5-2 示例]

== 例子 ==
=== WSGI应用程序 ===
{{{#!python
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!\n']


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!\n"
}}}
=== WSGI服务器 ===
{{{#!python
import os, sys

def run_with_cgi(application):

    environ = dict(os.environ.items())
    environ['wsgi.input'] = sys.stdin
    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):
        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
             sys.stdout.write('Status: %s\r\n' % status)
             for header in response_headers:
                 sys.stdout.write('%s: %s\r\n' % header)
             sys.stdout.write('\r\n')

        sys.stdout.write(data)
        sys.stdout.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[0], exc_info[1], exc_info[2]
            finally:
                exc_info = None # avoid dangling circular ref
        elif headers_set:
            raise AssertionError("Headers already set!")

        headers_set[:] = [status,response_headers]
        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()
}}}
=== WSGI中间件 ===
{{{#!python
from piglatin import piglatin

class LatinIter:

    """Transform iterated output to piglatin, if it's okay to do so

    Note that the "okayness" can change until the application yields
    its first non-empty string, so 'transform_ok' has to be a mutable
    truth value."""

    def __init__(self,result,transform_ok):
        if hasattr(result,'close'):
            self.close = result.close
        self._next = iter(result).next
        self.transform_ok = transform_ok

    def __iter__(self):
        return self

    def next(self):
        if self.transform_ok:
            return piglatin(self._next())
        else:
            return self._next()

class Latinator:

    # by default, don't transform output
    transform = False

    def __init__(self, application):
        self.application = application

    def __call__(self, environ, start_response):

        transform_ok = []

        def start_latin(status,response_headers,exc_info=None):

            # Reset ok flag, in case this is a repeat call
            transform_ok[:]=[]

            for name,value in response_headers:
                if name.lower()=='content-type' and value=='text/plain':
                    transform_ok.append(True)
                    # Strip content-length if present, else it'll be wrong
                    response_headers = [(name,value)
                        for name,value in response_headers
                            if name.lower()<>'content-length'
                    ]
                    break

            write = start_response(status,response_headers,exc_info)

            if transform_ok:
                def write_latin(data):
                    write(piglatin(data))
                return write_latin
            else:
                return write

        return LatinIter(self.application(environ,start_latin),transform_ok)


# Run foo_app under a Latinator's control, using the example CGI gateway
from foo_app import foo_app
run_with_cgi(Latinator(foo_app))
}}}

== 讨论 ==

TableOfContents

简介

wsgi 是一个 web 组件的接口规范. wsgi将 web 组件分为三类: web服务器,web中间件,web应用程序. 其目标是提高web组件的可重用性. wsgi 的设计目标是适合尽可能广泛的web应用, 较原始.

典型应用:

  •    1   app = A_WSGI_Application(...)
       2   app = Middleware1(app, ...)
       3   app = Middleware2(app, ...)
       4   ...
       5   server(app).serve_forever()
    

相关页面

规范

WSGI应用程序

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.

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

[#head-719d788ab1dd4f4bb61a26f59256d3a0dfc66cde-2 示例]

WSGI服务器

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 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.

[#head-747ebe56750a1de964d165b5b4a56e9eeb2f74a4-2 示例]

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.

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

[#head-229f9e55e6acb5e474a68f7293b978f55ff3beb5-2 示例]

例子

WSGI应用程序

   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服务器

   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中间件

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

讨论

WSGI (last edited 2009-12-25 07:17:11 by localhost)