As a Python Web developer, you don’t usually hear the term WSGI during the development phase of your application, but the WSGI specification is a hot topic when your application is ready to go live, and this article explains what WSGI is.

WSGI Full Web Server Gateway Interface is a generic programming Interface between a Web Server and a Web application (or framework) defined for the Python language. In plain English, WSGI is a protocol. Just as THE HTTP protocol defines the specification for client and server data transfer, WSGI defines the specification for working together between Web servers and Web applications.

Python Web application deployment scheme

Web frameworks like Flask or Django come with built-in Web Servers, Flask Run or Python manage.py RunServer can be used to start flask or Django built-in servers, respectively, during the local development phase.

When deploying applications in a production environment, you typically do not use servers built into the framework, but instead useGunicornuWSGITo deploy for better performance. Those of you who have deployed Python Web applications should be familiar with the following deployment architecture: the browser on the left and the server on the right. Inside the server, first throughNginxTo listen to80/443Port, when receiving a request from a client,NginxThe request is forwarded to the listener5000The port ofGunicorn/uWSGIServer, and the request is then delivered via the WSGI protocolFlask/DjangoThe framework, after processing the request logic inside the framework, will return the response information in the original way.

Nginx is high performance, you may ask, so why not deploy your application directly to Nginx and do a layer of forwarding via Gunicorn/uWSGI in between? Because Nginx doesn’t follow the WSGI specification, it can’t be easily combined with the Flask/Django framework like Gunicorn/uWSGI.

WSGI specification

Now that we know where WSGI is based on the Python Web application deployment architecture, let’s take a look at what the WSGI specification defines.

Just as HTTP has a client and a Server, WSGI has an Application and a Server, where Application refers to Flask, Django and other Web frameworks. Server refers to Web servers such as Gunicorn and uWSGI.

The WSGI protocol states that the Application side needs to be implemented as a callable object (function, class, etc.) with the following interface:

def simple_app(environ, start_response) :
    status = '200 OK'
    response_headers = [('Content-type'.'text/plain')]
    start_response(status, response_headers)
    return ['Hello world! \n']
Copy the code

Simple_app is the simplest Application. Environ is a dict that holds all HTTP request information and is provided by the Server. Start_response is a callable object. Also provided by the Server, Simple_app internally calls start_Response once, passing it the status code and response header as parameters. Simple_app eventually returns an iterable as HTTP Body content to the client.

Now that we know about the Application side interface, let’s look at the next server-side implementation that complies with the WSGI protocol:

import os


def wsgi_server(application) :
    environ = dict(os.environ.items())

    def start_response(status, response_headers) :
        print(f'status: {status}')
        print(f'response_headers: {response_headers}')

    result = application(environ, start_response)
    for data in result:
        print(f'response_body: {data}')
Copy the code

Wsgi_server takes an application as an argument and constructs environ and start_Response within it. Start_response is also defined as a function to be called internally by application. The wsGI_server function finally calls application and prints it.

Now that we have the Application side and the Server side, we can test out this simple WSGI Application example. Simply pass simple_app as an argument to wsGI_server and call wsGI_server:

wsgi_server(simple_app)
Copy the code

Executing the code above will result in the following print:

status: 200 OK
response_headers: [('Content-type', 'text/plain')]
response_body: Hello world!
Copy the code

Above, we have implemented WSGI compliant Application side and Server side respectively, and although the Application looks rudimentary, Python Web frameworks and Servers follow the same specification no matter how complex they are.

WSGI in action

After learning the WSGI specification, we can verify whether the Python Web framework we usually use really complies with this specification. Here we take the Flask framework source code as an example. You can look at the definition of the Flask at https://github.com/pallets/flask/blob/master/src/flask/app.py:

class Flask(Scaffold) :.def __call__(self, environ, start_response) :
        """The WSGI server calls the Flask application object as the WSGI application. This calls :meth:`wsgi_app`, which can be wrapped to apply middleware. """
        return self.wsgi_app(environ, start_response)
Copy the code

The Flask class internally implements the __call__ method to make the Flask instance object a callable object, and its interface implementation also conforms to the WSGI Application specification.

Jianghushini.cn