PythonWeb application: WSGI basics

Source: Internet
Author: User
Tags pprint
At the underlying layer of Django, Flask, Bottle, and all other Pythonweb frameworks is WebServerGatewayInterface (WSGI for short. For Python, WSGI is like Servlets for Java-a general specification used for web servers and allows different web servers and application frameworks to interact based on common APIs. However, for most cases, the Python version implementation is quite simple. WSGI is defined in PEP3333. if you want to learn more after reading this article ..

This article is based on the original translation of codenong network-Xiao Hao. please refer to the reprint requirements at the end of this article. welcome to join our paid contribution plan!

At the underlying layer of Django, Flask, Bottle, and all other Python web frameworks is the Web Server Gateway Interface (WSGI. For Python, WSGI is like Servlets for Java-a general specification used for web servers and allows different web servers and application frameworks to interact based on common APIs. However, for most cases, the Python version implementation is quite simple.

WSGI is defined in the PEP 3333 protocol. if you want to learn more after reading this article, I suggest you read the introduction first.

This article will introduce you to WSGI from the perspective of an application developer and show you how to develop applications directly through WSGI (if you can't wait ).

Your first WSGI application

Below are the most basic Python web applications:

def app(environ, start_fn):    start_fn('200 OK', [('Content-Type', 'text/plain')])    return ["Hello World!\n"]

That's it! The entire file. Name it app. py and run it on any WSGI compilable server. then you can getHello WorldWith a 200 response status code. You can use gunicorn to install and execute pip (pip install gunicorn ).Gunicorn app: app. This command tells gunicorn to obtain the callable WSGI from the application variables in the application module.

Just now, I was very excited. Can I run an application with only three lines of code? That must be a record in a certain sense (excluding PHP, because mod_php is working ). I bet you want to know more about it now.

So what is the most important part of a WSGI application?

  • A wsgi application is callable by Python, just like a function, a class, or a class instance with the _ call _ method

  • The callable application must accept two parameters:Environ, A Python dictionary containing necessary data,Start_fnIt can be called by itself.

  • The application must be able to callStart_fnAnd two parameters: Status Code (string), and a list expressed in two tuples in the header.

  • The application returns a convenient iteratable object that contains bytes in the response body. the stream part, for example, contains only "Hello, World !" String list. (IfAppIf it is a class, it can be completed in the _ iter _ method)

For example, the following two examples are equivalent to the first one:

class app(object):    def __init__(self, environ, start_fn):        self.environ = environ        self.start_fn = start_fn    def __iter__(self):        self.start_fn('200 OK', [('Content-Type', 'text/plain')])        yield "Hello World!\n"
class Application(object):    def __call__(self, environ, start_fn):        start_fn('200 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 relevant one is to write middleware.

Make it active

Middleware is a convenient way to extend the functionality of WSGI applications. Because you only need to provide an Callable object, you can wrap it in other functions at will.

For example, suppose we want to checkEnvironContent. We can easily create a middleware, as shown below:

import pprintdef handler(environ, start_fn):    start_fn('200 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_environIs a function that returns a function.EnvironThe parameter is decorated before the original callback is delayed.

In this way, the middleware and the processor do not need to know or care about each other. You can easily bindLog_environTo a Flask application, for example, because the Flask application is a WSGI application.

Other useful middleware designs:

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('500 Server Error', [('Content-Type', 'text/plain')])            return ['500 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

You can useReduceIt is applied to multiple middleware at a time.

# Applied from bottom to top on the way in, then top to bottom on the way outMIDDLEWARES = [wrap_query_params,               log_environ,               handle_error]app = reduce(lambda h, m: m(h), MIDDLEWARES, handler)

ExploitationStart_fnYou can also write the middleware for the decoration response body. Below is a content type header which isText/plainReverse the middleware of the output result.

def reverser(handler):    # A reverse function    rev = lambda it: it[::-1]    def _inner(environ, start_fn):        do_reverse = []  # Must be a reference type such as a list        # Override start_fn to check the content type and set a flag        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(map(rev, response)))            return response        finally:            if hasattr(response, 'close'):                response.close()    return _inner

BecauseStart_fnThe separation from the response body is a bit confusing, but it still works perfectly.

At the same time, please note that in order to strictly follow the WSGI specification, if there is, we must check in the response bodyCloseMethod and call it. The WSGI application may returnWriteA function is not an iteratable object that calls a processor. if you want your middleware to support earlier applications, you may need to handle this problem.

Once you start playing with the native WSGI, you will begin to understand why Python has a bunch of web frameworks. WSGI makes it easy to create something from the underlying layer. For example, you may be considering the following routing issues:

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 sets, it is very convenient to directly use WSGI to create the wheel.

  • Template Library: input any template you like (for example, Jinja2, Pystashe) and return the rendered template from your processor!

  • Use a library to help your Routes, 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 libraries.

Of course, for non-professional applications, you may also want to use the framework. In that case, some special such examples can also be reasonably solved.

What about the server?

There are many methods to serve WSGI applications. We have already discussed Gunicorn, a good choice. UWSGI is another good choice. However, make sure that nginx and other things are set before service static things, and you should have a fixed start node.

The above is the details of the Python Web application: WSGI basics. For more information, see other related articles in the first PHP community!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.