Differences between revisions 2 and 4 (spanning 2 versions)
Revision 2 as of 2006-02-03 11:58:45
Size: 756
Editor: hoxide
Comment:
Revision 4 as of 2006-08-22 06:17:40
Size: 6247
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应用程序 ===
=== WSGI服务器 ===
=== WSGI中间件 ===

== 例子 ==
=== 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应用程序

WSGI服务器

WSGI中间件

例子

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)