Today on the home page of Git.oschina see them launch demo platform, where Python's demo platform supports WSGI interface applications. Although the demo platform didn't even run out of its own examples, it succeeded in WSGI my curiosity about the company. Understanding, the understanding of the mechanism, summarized as follows. If there is something wrong, also look treatise.
Why the WSGI?
The people who wrote the Web application should have an understanding of CGI, and we know that the entire CGI is "Common Gateway Interface", the Universal Gateway Interface. Yes, the WSGI here is the Web application interface "Python Web Server Gateway Interface" only for Python. By this analogy, we must have some understanding of his status.
It is just an interface definition: it is not responsible for the implementation of the server, nor is it responsible for the implementation of the Web application, it is just a two-way interface of the Convention. Therefore, it is not another Web application framework, and the usual Web application framework is equivalent to an implementation of the WSGI Web application side.
What are the benefits of doing this? The explanation in PEP 0333 is that in order to implement a Java Servelet-like API, applications that follow that interface have a wider applicability. Yes, with this interface, you don't have to think about how the server support for Python is implemented--a server that is implemented directly with Python? Server embedded in Python? or through the Gateway Interface (CGI, Fastcgi ...) --The application has a good applicability. Just like the beginning of today's story, we met the cloud platform, which provides support for the WSGI interface, so as long as the application is based on the WSGI, the application can run directly.
In addition, the design of WSGI also provides another possibility, that is middleware (middleware). Alternatively, we can write some modules that are compatible with both server and application, and we can deploy them on the server side or on the application side, such as caching, character encoding conversion, application routing based on URLs. This design pattern is the result of the WSGI reducing the coupling between the server and the application, and it greatly increases the flexibility of the design from another angle.
WSGI Implementation Summary
In the previous section, a brief introduction to WSGI was made. Here, from the application, server, middleware three angles to the WSGI a little deeper, so that we have a more specific impression of it.
1) Application End
WSGI requires that the application side must provide an entity that can be called (PEP 0333 uses object, and the document specifically explains that this differs from object instance), which can be: a function, a method, A class, or an object with the __call__ method (object instance).
Here are two examples of Web application implementations, a function, a class:
def Simple_app (environ, start_response): status = " 200 OK " response_headers = [( Span style= "color: #800000;" > ' content-type ' , text/plain '
The function above does not handle the environ from the server side, just directly to the request to do a "OK" response; It should be noted that after the server calls (call), it returns a list (with "[]" included) to ensure the results of it Erable. The following class functions are similar. The following appclass as an application entity, when implemented, the server calls the class (call), in fact, he was instantiated (can refer to the implementation code behind the server side), as we have seen, the call is also the return value of the iteration-- Although only one iteration is iterative.
classAppclass: def __init__(self, Environ, start_response): Self.environ=environ Self.start=Start_responsedef __iter__(self): status='OK'response_headers= [('Content-type','Text/plain')] Self.start (status, Response_headers)yield "Hello world!\n" """in fact, the Interator ' ends ' here because of no more yield field " " "
When you use an object as an application entity, you can refer to the method above that uses function as the entity: Add the __call__ method to the class, and the return value is iterable (such as return [something]).
The two parameters to application are two positional parameters (not named parameters): A Dictionary object that holds the CGI environment variable, and a callable entity (which needs to give it three positional parameters, two must, one optional).
Where the callable entity (Start_response in the previous precedent) must be called once, and both of the required parameters are "HTTP response status (STR type)" and "HTTP response Header (List of tuples)" An optional parameter, Exc_info, must be a Python sys.exc_info () tuple to be used only if an error message needs to be displayed. Full Call: Start_response (status, Response_headers,exc_info).
2) Server Side
Here is a simple WSGI container from PEP 0333, suitable for Python as a CGI application framework.
ImportOS, sysdefrun_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'] =TrueifEnviron.get ('HTTPS','if')inch(' on','1'): environ['Wsgi.url_scheme'] ='HTTPS' Else: environ['Wsgi.url_scheme'] ='http'Headers_set=[] headers_sent= [] defWrite (data):if notHeaders_set:RaiseAssertionerror ("write () before Start_response ()") elif notheaders_sent:#before the first output, send the stored headersStatus, Response_headers = headers_sent[:] =Headers_set Sys.stdout.write ('Status:%s\r\n'%status) forHeaderinchResponse_headers:sys.stdout.write ('%s:%s\r\n'%header) Sys.stdout.write ('\ r \ n') sys.stdout.write (data) Sys.stdout.flush ()defStart_response (Status, Response_headers, exc_info=None):ifExc_info:Try: ifheaders_sent:#re-raise Original exception if headers sent RaiseExc_info[0], exc_info[1], exc_info[2] finally: Exc_info= None#Avoid dangling circular ref elifHeaders_set:RaiseAssertionerror ("Headers already set!") headers_set[:]=[Status, Response_headers]returnWrite result=application (environ, start_response)
Try: forDatainchResult:ifData#don ' t send headers until body appearsWrite (data)if notHeaders_sent:write ("')#Send headers Now if body is empty finally: ifHasattr (Result,'Close'): Result.close ()
The above container, presumably implemented: a) puts the CGI environment variable into Dictionary object (environ) for use by the application entity, and B) defines the Start_response method for the application entity to invoke c) Call the application entity, process the Web request, D) application The return result, and the HTTP response HEADER set through Start_response, write to stdout--like other CGI is actually being sent to the Web page.
3) as middleware
Because of the loose coupling features of WSGI, we can easily insert any intermediate plug-ins before application and server, and implement some special functions without the need to change the server and application. However, this module, which is placed in the "middle" of the Server and application, is not a middleware here, or it can only be considered a special middleware, because it only implements the APP middleware defined in PEP 0333. The function of the lication side. This is only implemented on one side of the middleware, which requires a special declaration at the time of release.
As agreed in PEP 0333, middleware is a module that can be implemented on the Server side and implemented on the application side. Therefore, in the design, the characteristics of both sides should be given due consideration. Fortunately, the WSGI interface is designed to be simple enough.
classRouter ():def __init__(self): Self.path_info= {} defroute (self, Environ, start_response): Application= self.path_info[environ['Path_info']] returnapplication (environ, start_response)def __call__(self, path):defWrapper (application): Self.path_info[path]=ApplicationreturnWrapper
"" "The above is the middleware" ""
Router=Router () @router ('/world')defWorld (Environ, start_response): status='OK'Output='world!'start_response (status, Response_headers)return[Output] @router ('/hello') defhello (environ, start_response): status='OK'Output='Hello'response_headers= [('Content-type','Text/plain'), ('Content-length', str (output))] start_response (status, Response_headers)return[Output]
Simply explain:
-As application, we instantiate an object with Router. Then the "Path-app" to register, according to the different PATH, we want to choose which APP. Next, the Router.route () is fed to the Server as a callable entity on the application side. When a request arrives, the application is selected and executed according to the registered "Path-app".
-Similar to Server side, we need to instantiate and complete the registration first. Then, for example, take the WSGI container we implemented in the previous section, for example, we need to modify result = Router.route (environ, start_response), and also complete the router function.
Here is another, an example of implementing postprocessor, and adding a header to the HTTP header returned by application.
defMyApp (environ, start_response): Response_headers= [('Content-type','Text/plain')] Start_response ('OK', Response_headers)return['Check the headers!']classMiddleware:def __init__(self, app): Self.wrapped_app=appdef __call__(self, Environ, start_response):defCustom_start_response (status, headers, exc_info=None): Headers.append (('X-a-simple-token',"1234567890")) returnstart_response (status, headers, exc_info)returnSelf.wrapped_app (environ, custom_start_response) app= Middleware (MyApp)
This is accomplished by rewriting the entities passed to application to achieve the purpose of postprocess.
Other resources:
-Some details of WSGI, including the application list or something: http://wsgi.readthedocs.org/en/latest/
-Multi-threaded WEB server with WSGI support, based on simplehttpserver:http://www.owlfish.com/software/wsgiutils/
-Paste provides a good foundation for building WSGI-based WEB applications or frameworks
-The official WSGI implementation reference: Https://pypi.python.org/pypi/wsgiref
-WSGI Chinese Wiki:http://wiki.woodpecker.org.cn/moin/wsgi of Woodpecker community
-Paste as famous as the basic architecture: https://pypi.python.org/pypi/Pylons/1.0
-Python is currently the most popular of the three WEB frameworks: Turbogears,django,web2py. +1, code at K-level service Small frame: webpy.
The "CGI" interface in Python--wsgi