WSGI agreement
First, clarify the following concepts: WSGI: WSGI is not a Server, Python module, framework, API, or any piece of software, but a specification that describes how the Web Server communicates with Web Applications. The specifications for the Server and application are detailed in PEP 3333. To implement WSGI, you must implement both Web Server and Web Application. The current Web frameworks running on WSGI include Bottle, Flask and Django. Uwsgi: As a communication protocol, it is the exclusive protocol of THE uWSGI server and is used to define the type of information transmitted. The first 4 bytes of each uWSGI packet are the description of the type of information transmitted, which is different from the WSGI protocol. This protocol is said to be 10 times faster than fcGI. UWSGI: a Web server that implements WSGI, uWSGI, HTTP, and so on.
WSGI protocol mainly consists of server and Application:
-
WSGI server
Responsible for receiving requests from the client, willrequest
Forwarded toapplication
That will beapplication
The returnedresponse
Return to the client; -
WSGI application
Received by theserver
forwardingrequest
, process the request and return the result toserver
.application
Can include multiple stacks of middleware (middlewares
), these middleware need to implement both server and application, so they can mediate between WSGI server and WSGI application: middleware acts as the application for the server, and middleware acts as the server for the application.
WSGI protocol actually defines a decoupling specification of server and application, that is, there can be multiple servers implementing WSGI Server and multiple frameworks implementing WSGI Application. You can then choose any combination of server and Application to implement your own Web application. For example, uWSGI and Gunicorn are servers that implement the WSGI Server protocol, while Django and Flask are Web frameworks that implement the WSGI Application protocol. They can be used together according to the actual situation of the project.
Wsgi. PNG – 22.9 kB
The Flask framework, like Django, has its own implementation of a simple WSGI Server, which is generally used for server debugging, and other WSGI servers are recommended for production environments.
Implementation of the WSGI protocol
Using Django as an example, take a look at the implementation process of WSGI.
django WSGI application
The WSGI Application should be implemented as a callable object, such as a function, method, class (including the ‘call’ method). Two parameters need to be received:
- A dictionary, which can contain information about a client request as well as other information, can be thought of as the request context, commonly called
environment
(The code is often abbreviated asenviron
,env
) - An application that sends HTTP response status (
HTTP status
), response headers (HTTP headers
)
The callback function returns the response status and the response header to the server, along with the response body, which is iterable and contains multiple strings. Here is the implementation of an application in Django:
class WSGIHandler(base.BaseHandler): initLock = Lock() request_class = WSGIRequest def __call__(self, environ, start_response): If self._request_middleware is None: with self. InitLock: try: # Check that middleware is still uninitialized. if self._request_middleware is None: self.load_middleware() except: # Unload whatever middleware we got self._request_middleware = None raise set_script_prefix(get_script_name(environ)) # Request_started. Send (sender=self.__class__, environ=environ) request = self.request_class(environ) except UnicodeDecodeError: logger.warning('Bad Request (UnicodeDecodeError)', exc_info=sys.exc_info(), extra={'status_code': 400,}) response = http.HttpResponseBadRequest() else: response = self.get_response(request) response._handler_class = self.__class__ status = '%s %s' % (response.status_code, response.reason_phrase) response_headers = [(str(k), str(v)) for k, v in response.items()] for c in response.cookies.values(): Response_headers. Append ((STR (' set-cookie '), STR (c. utput(header=')))) ')) Respont_response (force_str(status), response_headers) if getattr(response, 'file_to_stream', response_headers) None) is not None and environ.get('wsgi.file_wrapper'): response = environ['wsgi.file_wrapper'](response.file_to_stream) return responseCopy the code
It can be seen that the process of application includes:
- Load all middleware and perform frame-related operations, set the current thread script prefix, send request start signal;
- Handle requests, calls
get_response()
Method to process the current request. The main logic of this method is to passurlconf
Find the correspondingview
andcallback
, in order to execute variousmiddleware
andcallback
. - Call by
server
The incomingstart_response()
The method will respondheader
withstatus
Back to theserver
. - Return the response body
django WSGI Server
It is responsible for getting the HTTP request and passing it to the WSGI Application, which processes the request and returns a response. Take a look at the implementation using Djangos built-in Server as an example. When running a Django project through RunServer, the following run method is called at startup, creating an instance of WSGIServer, and then calling its serve_forever() method to start the service.
def run(addr, port, wsgi_handler, ipv6=False, threading=False): server_address = (addr, port) if threading: httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {}) else: HTTPD = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) if threading: httpd.daemon_threads = True httpd.set_app(wsgi_handler) httpd.serve_forever()Copy the code
The key classes and methods in the WSGI Server server process are represented below.
Xiong (2). The PNG – 93.7 kB
- WSGIServer
run()
Method createsWSGIServer
Instance, whose main function is to receive client requests and pass them toapplication
And thenapplication
The returnedresponse
Return to the client.- Specified when creating the instance
HTTP
The request ofhandler
:WSGIRequestHandler
class - through
set_app
andget_app
Method to set and getWSGIApplication
The instancewsgi_handler
- Call when processing an HTTP request
handler_request
Method is createdWSGIRequestHandler
Instance processing HTTP requests. -
WSGIServer
In theget_request
Methods bysocket
Accept request data
- Specified when creating the instance
- WSGIRequestHandler
- by
WSGIServer
In the callhandle_request
Create instance when passed inrequest
,cient_address
,WSGIServer
Three parameters,__init__
The method will also call itself when instantiatedhandle
methods -
handle
Method createsServerHandler
Instance, and then invoke itrun
Method to process the request
- by
- ServerHandler
-
WSGIRequestHandler
In itshandle
Method callrun
Method, passed inself.server.get_app()
Parameter, obtainWSGIApplication
, and then calls the instance (__call__
),response
, which is passed instart_response
Callback, used to process the returnheader
andstatus
. - through
application
To obtainresponse
Later, throughfinish_response
returnresponse
-
- WSGIHandler
-
WSGI
In the agreementapplication
, receives two parameters,environ
The dictionary contains information about the client request as well as other information that can be considered the request context,start_response
Used to send backstatus
andheader
The callback function of
-
Although the WSGI Server above involves multiple class implementations and references, the principle is to call WSGIHandler, pass in the request parameters and the callback method start_response(), and return the response to the client.
django simple_server
Django’s simple_server.py module implements a simple HTTP server and provides a simple demo that can be run directly and display the environment variables involved in the request in the browser. This includes all the components of the entire HTTP request described above: ServerHandler, WSGIServer, WSGIRequestHandler, and a simplified version of WSGIApplication represented by Demo_app. Take a look at the process:
if __name__ == '__main__': Create WSGIServer instance from make_server demo_app httpd = make_server('', 8000, demo_app) sa = httpd.socket.getsockname() print("Serving HTTP on", sa[0], "port", sa[1], "..." ) import webbrowser webbrowser.open('http://localhost:8000/xyz? HTTPD. Handle_request () # serve one request, then exit httpd.server_close() def make_server( host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler ): """Create a new WSGI server listening on `host` and `port` for `app`""" server = server_class((host, port), Handler_class) server.set_app(app) return server # demo_app(environ,start_response): from io import StringIO stdout = StringIO() print("Hello world!" , file=stdout) print(file=stdout) h = sorted(environ.items()) for k,v in h: print(k,'=',repr(v), file=stdout) start_response("200 OK", [('Content-Type','text/plain; charset=utf-8')]) return [stdout.getvalue().encode("utf-8")]Copy the code
Demo_app () represents a simple WSGI Application implementation that creates an instance of WSGIServer using the make_server() method and calls its handle_Request () method, which calls Demo_app () to handle the request, And eventually returns a response.
uWSGI
UWSGI aims to develop a complete solution for web applications that deploy distributed clusters. Primarily web oriented and standard services. Because of its extensibility, it can be extended indefinitely to support more platforms and languages. UWSGI is a Web server that implements THE WSGI protocol, uWSGI protocol, HTTP protocol, etc. The key features of uWSGI are:
- Super fast performance
- Low memory footprint
- more
app
management - Detailed logging capabilities (available for analysis
app
Performance and bottlenecks) - Highly customizable (memory size limit, restart after a certain number of times, etc.)
UWSGI server implements the server part based on the uWSGI protocol. We only need to specify the application address in the uWSGI configuration file, and uWSGI can directly communicate with the WSGI application in the application framework.
Nginx and UWSGI communicate with each other using Python WSGI