0.1 WSGI concept
Enhanced recommendation from Python: PEP-3333, developed from PEP-333 (to support PYTHON 3) for Web Server Gateway Interface
There are various Web application frameworks in Python, and different application frameworks limit the use of their Web servers. Compared to JAVA, there are many web development frameworks, but since the advent of the Servlet API, JAVA Web frameworks can all run on web servers that support the Servlet API. The WSGI protocol acts as the SRVlet API, which defines the interface between the application or framework and the Web server, enabling python’s Web framework to run on any web server that supports the WSGI protocol.
So what are the benefits of following the WSGI protocol to develop frameworks, applications, Web servers, etc.
At least with a clear domain division, we don’t need to develop a Web application or framework at the same time to think about implementing the functionality of the Web server, focus on each domain, reduce the duplication of wheels.
Because of the portability and flexibility of the project, we should no longer consider that only one Web framework can be used in the project. When our Web server complies with the WSGI protocol, the choice of application layer framework is not an issue.
0.2 WSGI protocol content
The WSGI protocol divides the entire Web Server into three parts: Server, Application, and Middleware.
0.2.1. Server
The Server invokes the application object every time it receives a request from the HTTP client. What you need to implement is a function that writes the parameters, headers, and metadata contained in the request to a dictionary, and that returns data to the client, passing it into the Application.
This Server is where we handle all of our Web requests, both externally to handle concurrent requests, and for classes to load our application code to handle each request logic
Here we implement a CGI process in Python that takes a request parameter from an environment variable and uses the CGI process to process the request output to standard output.
import os, sys enc, esc = sys.getfilesystemencoding(), 'surrogateescape' def unicode_to_wsgi(u): # Convert an environment variable to a WSGI "bytes-as-unicode" string return u.encode(enc, esc).decode('iso-8859-1') def wsgi_to_bytes(s): return s.encode('iso-8859-1') def run_with_cgi(application): environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()} environ['wsgi.input'] = sys.stdin.buffer environ['wsgi.errors'] = sys.stderr environ['wsgi.version'] = (1, 0) environ['wsgi.multithread'] = False environ['wsgi.multiprocess'] = True environ['wsgi.run_once'] = True if environ.get('HTTPS', 'off') in ('on', '1'): environ['wsgi.url_scheme'] = 'https' else: environ['wsgi.url_scheme'] = 'http' headers_set = [] headers_sent = [] def write(data): out = sys.stdout.buffer if not headers_set: raise AssertionError("write() before start_response()") elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set out.write(wsgi_to_bytes('Status: %s\r\n' % status)) for header in response_headers: out.write(wsgi_to_bytes('%s: %s\r\n' % header)) out.write(wsgi_to_bytes('\r\n')) out.write(data) out.flush() def start_response(status, response_headers, exc_info=None): if exc_info: try: if headers_sent: # Re-raise original exception if headers sent raise exc_info[1].with_traceback(exc_info[2]) finally: exc_info = None # avoid dangling circular ref elif headers_set: raise AssertionError("Headers already set!" ) headers_set[:] = [status, response_headers] # Note: error checking on the headers should happen here, # *after* the headers are set. That way, if an error # occurs, start_response can only be re-called with # exc_info set. return write result = application(environ, start_response) try: for data in result: if data: # don't send headers until body appears write(data) if not headers_sent: write('') # send headers now if body was empty finally: if hasattr(result, 'close'): result.close()Copy the code
0.2.2. Application
An application is a simple callable object that takes two arguments. It can be a function, a method, a class, or an instance that implements call. The application object must be able to be called multiple times, and the Web server will call it repeatedly.
Basic structure:
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello World!']
Copy the code
There are two implementations of Application: functions and classes
def simple_app(environ, start_response): Status = '200 OK' response_headers = [(' content-type ', 'text/plain')] start_response(status, response_headers) return b"Hello world! \n" class AppClass: """ Generates an instance object of AppClass, which is a generator object. When we iterate over the object, the __iter__ method is executed to achieve the effect of repeated execution. Of course we want to do this by executing the instance object, which implements the __call__ method. """ def __init__(self, environ, start_response): self.environ = environ self.start = start_response def __iter__(self): status = '200 OK' response_headers = [('Content-type', 'text/plain')] self.start(status, response_headers) yield b"Hello world! \n"Copy the code
0.2.3. Middleware
Middleware is a component that can interact with both ends. It can also be regarded as an Application. It accepts an Application as a parameter and returns an Application, which makes use of the nesting property of Application. App = mw1(mw2(app)
-
Rewrite environ and route request objects to different application objects based on urls
-
Support for multiple applications or frameworks to run sequentially in the same process
-
Supports load balancing and remote processing by forwarding requests and responses
-
Support for postprocessing of content
Some extensions of the WSGI protocol
0.3.1 About uWSGI and uWSGI
UWSG a Web server that implements the WSGI interface.
Uwsgi is a binary protocol used for communication between two Web servers. It is commonly deployed together with UWSGI using Nginx. Nginx is used for communication between UWSGI using UWSGI, and Nginx is responsible for converting HTTP protocol packages into UWSGI protocol packages.
Of course, uWSGI can be independent of Nginx, but the client-to-server protocol is usually HTTP, so there are two options on the uWSGI server: It parses THE HTTP protocol to the UWSGI protocol itself. It sets up an HTTP process to accept the client request and parse it and then pass it to the work of each UWSGI server using the UWSGI protocol. The other is to use HTTP for the entire process
0.3.1 WsGI application parameter envrion
In fact, the WSGI protocol compliant server passes to the application a dictionary of all the requested content, which contains an HTTP request header, route, request body and other parameters
0.3.2 About uWSGI and uWSGI
Chinese Translation document: [https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Options.html](https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Optio ns.html)
Of course, uWSGI can be independent of Nginx, but the client-to-server protocol is usually HTTP, so there are two options on the uWSGI server: It parses THE HTTP protocol to the UWSGI protocol itself. It sets up an HTTP process to accept the client request and parse it and then pass it to the work of each UWSGI server using the UWSGI protocol. The other is to use HTTP for the entire process.
Uwsgi is a binary protocol used for communication between two Web servers. It is commonly deployed together with UWSGI using Nginx. Nginx is used for communication between UWSGI using UWSGI, and Nginx is responsible for converting HTTP protocol packages into UWSGI protocol packages.
UWSGI is a Web server that implements the WSGI interface.
This is my first original article on Zhihu. I collected my previous study notes and added my own understanding. I hope it will be helpful to the future readers.