This article by the Code Rural Network – Schohau original translation, reproduced please see the text at the end of the reprint requirements, welcome to participate in our paid contribution program!
At the bottom of django,flask,bottle and all other Python web frameworks is the Web Server Gateway Interface, referred to as WSGI. Wsgi for Python is like Servlets to Java-A common specification for Web servers that allows different Web servers and application frameworks to interact based on common APIs. However, for most things, the Python version implementation is fairly straightforward.
WSGI is defined in THE PEP 3333 protocol, and if you want to learn more after reading this article, the author suggests that readers read the introduction first.
This article will introduce you to the WSGI instructions from an application developer's perspective and show you how to develop the application directly through WSGI (if you can't wait).
Your first WSGI application
Here's the most basic Python web app:
def app (environ, START_FN): start_fn (' OK ', [(' Content-type ', ' Text/plain ')] return ["Hello world!\n"]
That's it! The entire file. Name it app.py and then run it on any WSGI compiled server, then you can get a Hello world and accompany a 200 response status code. You can use Gunicorn to complete the installation and execution of Gunicorn App:appvia Pip (Pip install gunicorn). This command tells Gunicorn to get the callable Wsgi from application variables in the application module.
Just now, very excited. Just three lines of code to run an app? That must be a record of some kind (not including PHP, because mod_php is working). I bet you want to go deeper now.
So what is the most important part of a WSGI application?
A WSGI application is Python callable, like a function, a class, or an instance of a class with a __call__ method
The callable application must accept two parameters:environ, a python dictionary that contains the necessary data,START_FN, which is callable by itself.
The application must be able to invoke Start_fn and two parameters: a status code (string), and a list of headers expressed in two tuples.
The application returns a convenient, iterative object that contains bytes in the return body--for example, each one contains only "hello,world! "A list of strings. (If the app is a class, it can be done in the __iter__ method)
For example the following two examples and the first one are equivalent:
Class App (object): def __init__ (self, Environ, start_fn): Self.environ = environ self.start_fn = start_fn< C3/>def __iter__ (self): self.start_fn (' K OK ', [(' Content-type ', ' Text/plain ')] yield "Hello world!\n"
Class Application (Object): def __call__ (self, Environ, start_fn): start_fn (' OK ', [' content-type ', ' text/ Plain ')]) yield "Hello world!\n" app = Application ()
You may have begun to think about what you can do with these things, but the most likely related one is to write middleware.
Make it active.
Middleware is a convenient way to extend WSGI application functionality. Because you only have to provide a callable object, you can wrap it in any other function.
For example, suppose we want to test the contents of environ . We can easily create a middleware to do as follows:
Import Pprintdef handler (environ, START_FN): start_fn (' $ OK ', [(' Content-type ', ' Text/plain ')] return [" Hello world!\n "]def Log_environ (handler): def _inner (environ, START_FN): pprint.pprint (environ) return Handler (environ, START_FN) return _innerapp = Log_environ (handler)
Here,Log_environ is a function that returns a function that decorates the parameter before the environ parameter delays the original callback.
The advantage of writing middleware like this is that middleware and processors don't need to know or care about each other. You can easily bind Log_environ to a flask application, for example, because the Flask app is a WSGI app.
Some other useful middleware designs are:
Import Pprintdef Handle_error (handler): def _inner (environ, START_FN): try: return handler (environ, START_FN) except Exception as e: print e # Log error start_fn (' Server error ', [' Content-type ', ' Text/plain ')] return [' $ Server Error '] return _innerdef wrap_query_params (handler): def _inner ( Environ, START_FN): qs = environ.get (' query_string ') environ[' query_params '] = Urlparse.parse_qs (QS) return handler (environ, START_FN) return _inner
If you don't want your files to have a large pyramid bottom, you can use reduce once to apply to multiple middleware.
# Applied from bottom to top on the same as, then top to bottom on the Outmiddlewares = [Wrap_query_params, log_en Viron, Handle_error]app = reduce (lambda h, m:m (h), Middlewares, Handler)
Take advantage of the advantages of the start_fn parameter You can also write the middleware that decorates the response body. The following is a content-type header that is a middleware for text/plain to invert output results.
def reverser (handler): # A Reverse function rev = Lambda It:it[::-1] def _inner (environ, START_FN): do_ reverse = [] # must is a reference type such as a list # Override START_FN to check the content type and set a FLA G def start_reverser (status, headers): for Name, value in headers: if (name.lower () = = ' Content-type ' and value.lower () = = ' Text/plain '): do_reverse.append (True) Break # Remember-to-call ' START_FN ' START_FN (status, headers) response = Handler (environ, Start_reverser) try: if Do_reverse: Return List (Rev (Rev, Response)) return response finally: if hasattr (response, ' close '): Response.close () return _inner
The separation of the START_FN and the response body is a bit confusing, but it works perfectly.
Also note that in order to strictly follow the WSGI specification, if present, we must check the close method in the response body and invoke it. It is possible for an WSGI application to return a write function instead of an iterative object that calls the processor, which you might need to deal with if you want your middleware to support earlier applications.
Once you start playing with the native Wsgi, you begin to understand why Python has a bunch of web frameworks. Wsgi makes it easy to make something from the bottom. For example, you might be considering the following routing problem:
Routes = { '/': Home_handler, '/about ': About_handler,}class Application (object): def __init__ (self, Routes): self.routes = Routes def not_found (self, Environ, start_fn): start_fn (' 404 Not Found ', [(' Content-type ', ' Text/plain ')] return [' 404 Not Found '] def __call__ (self, Environ, START_FN): handler = Self.routes.get (Environ.get (' path_info ')) or Self.not_found return handler (environ, START_FN)
If you like the flexibility of the following resource collection, it is very convenient to use WSGI to make the wheel directly.
Template gallery: Put any template you like (for example, Jinja2,pystashe) and return the rendered template from your processor!
Use a library to help with your routing, such as routes or Werkzeug's routing. In fact, if you want to use WSGI easily, take a look at Werkzeug.
Use any flask or similar database migration library.
Of course, for non-professional applications, you may also want to use the framework, so that some of the special examples can be reasonably solved.
What about servers?
There are many ways to service WSGI applications. We've talked about Gunicorn, a pretty good choice. Uwsgi is another good choice. But make sure to set up the Nginx class before serving these static things, and you should have a fixed start node.