Moved middleware introduction to "Specification Overview" section,
adding a code example for a trivial middleware component.
This commit is contained in:
parent
45b26f3c1f
commit
3f6ca60005
126
pep-0333.txt
126
pep-0333.txt
|
@ -125,6 +125,17 @@ Other servers and gateways may use configuration files or other
|
|||
mechanisms to specify where an application object should be
|
||||
imported from, or otherwise obtained.
|
||||
|
||||
In addition to "pure" servers/gateways and applications/frameworks,
|
||||
it is also possible to create "middleware" components that implement
|
||||
both sides of this specification. Such components act as an
|
||||
application to their containing server, and as a server to a
|
||||
contained application, and can be used to provide extended APIs,
|
||||
content transformation, navigation, and other useful functions.
|
||||
|
||||
|
||||
The Application/Framework Side
|
||||
------------------------------
|
||||
|
||||
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,
|
||||
|
@ -184,6 +195,10 @@ invoking a callable must *not* have any dependency on what kind of
|
|||
callable was provided to it. Callables are only to be called, not
|
||||
introspected upon.
|
||||
|
||||
|
||||
The Server/Gateway Side
|
||||
-----------------------
|
||||
|
||||
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
|
||||
|
@ -254,8 +269,89 @@ server.
|
|||
if hasattr(result,'close'):
|
||||
result.close()
|
||||
|
||||
In the next section, we will specify the precise semantics that
|
||||
these illustrations are examples of.
|
||||
|
||||
Middleware: Components that Play Both Sides
|
||||
-------------------------------------------
|
||||
|
||||
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:
|
||||
|
||||
* 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
|
||||
|
||||
* 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".
|
||||
|
||||
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.)
|
||||
|
||||
::
|
||||
|
||||
from piglatin import piglatin
|
||||
|
||||
class Latinator:
|
||||
|
||||
# by default, don't transform output
|
||||
transform = str
|
||||
|
||||
def __init__(self, application):
|
||||
self.application = application
|
||||
|
||||
def __call__(environ, start_response):
|
||||
|
||||
def write_latin(data):
|
||||
self.write(self.transform(data))
|
||||
|
||||
def start_latin(status,headers,exc_info=None):
|
||||
|
||||
for name,value in headers:
|
||||
if name.lower()=='content-type' and value=='text/plain':
|
||||
self.transform = piglatin
|
||||
# Strip content-length if present, else it'll be wrong
|
||||
headers = [(name,value)
|
||||
for name,value in headers
|
||||
if name.lower()<>'content-length'
|
||||
]
|
||||
break
|
||||
|
||||
self.write = start_response(status,headers,exc_info)
|
||||
return write_latin
|
||||
|
||||
for data in self.application(environ,start_latin):
|
||||
yield self.transform(data)
|
||||
|
||||
# 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))
|
||||
|
||||
|
||||
|
||||
Specification Details
|
||||
|
@ -851,6 +947,8 @@ of its use::
|
|||
start_response(status, headers)
|
||||
return ["normal body goes here"]
|
||||
except:
|
||||
# XXX should trap runtime issues like MemoryError, KeyboardInterrupt
|
||||
# in a separate handler before this bare 'except:'...
|
||||
status = "500 Oops"
|
||||
headers = [("content-type","text/plain")]
|
||||
start_response(status, headers, sys.exc_info())
|
||||
|
@ -976,30 +1074,6 @@ course, applications should cache such configuration, to avoid having
|
|||
to re-read it upon each invocation.)
|
||||
|
||||
|
||||
Middleware
|
||||
----------
|
||||
|
||||
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:
|
||||
|
||||
* 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
|
||||
|
||||
* Perform content postprocessing, such as applying XSL stylesheets
|
||||
|
||||
Given the existence of applications and servers conforming to this
|
||||
specification, the appearance of such reusable middleware becomes
|
||||
a possibility.
|
||||
|
||||
|
||||
Supporting Older (<2.2) Versions of Python
|
||||
------------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue