The python video tutorial section introduces what is WSGI.
I have written python web for a few years, but I still don’t know what WSGI is, is there a lot of people. It's normal, because as a developer, you rarely need to understand what wsgi is and be able to make a website.
But if you want to write a web framework for fun, you have to learn about wsgi.
To recap, when we use python for web development, we generally develop based on a certain web framework, such as django or flask. After the business development is completed, it must be deployed to a server to provide external access.
At this time, if you search the Internet, they will tell you that you need to use gunicorn or uwsgi to deploy. So what are gunicorn and uwsgi?
Look at this picture, you will understand, I found the picture from the Internet
The role played by uwsgi or gunicorn here is the role of a web server. The server here is a software-level server for processing HTTP requests sent by the browser and returning the response results to the front end. The main task of the web framework is to process the business logic to generate the results to the web server, and then the web server returns to the browser.
The communication between the web framework and the web server needs to follow a set of specifications, this specification is WSGI.
Why is there such a set of specifications? The standard is to unify the standard and make it easy for everyone to use
Imagine that our mobile phone charging interface is now Type-c. Type-c is a specification. Mobile phone manufacturers produce mobile phones according to this specification. Charger manufacturers produce chargers according to Type-c specifications. Mobile phones from different manufacturers It can be used with chargers from different manufacturers. However, Apple has established its own set of specifications, which finally caused the Android charger to fail to charge Apple.
So how to write an application (framework) program and server that conforms to the WSGI specification?
As shown in the figure above, on the left is the web server, and on the right is the web framework, or application.
Application
WSGI stipulates that the application must be a callable object (the callable object can be a function, a class, or an instance object that implements __call__), and must accept two parameters, the return value of the object Must be an iterable object.
We can write an example of the simplest application
HELLO_WORLD = b"Hello world!\n"def application(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers) return [HELLO_WORLD]复制代码
application is a function, it must be a callable object, and then receives two parameters, the two parameters are: environ and start_response
environ is a dictionary that stores all content related to the HTTP request, such as headers, request parameters, etc.
start_response is a function passed by the WSGI server to pass the response header and status code to the server.
Calling the start_response function is responsible for passing the response header and status code to the server, and the response body is returned to the server by the application function. A complete http response is provided by these two functions.
But any web framework that implements wsgi will have such a callable object
What the server
WSGI server does is each time it receives an HTTP request, constructs an environ object, then calls the application object, and finally returns the HTTP Response to the browser.
The following is a complete wsgi server code
import socketimport sysfrom io import StringIOclass WSGIServer(object):
address_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
request_queue_size = 1
def __init__(self, server_address):
# Create a listening socket
self.listen_socket = listen_socket = socket.socket(
self.address_family,
self.socket_type
) # Allow to reuse the same address
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Bind
listen_socket.bind(server_address) # Activate
listen_socket.listen(self.request_queue_size) # Get server host name and port
host, port = self.listen_socket.getsockname()[:2]
self.server_name = socket.getfqdn(host)
self.server_port = port # Return headers set by Web framework/Web application
self.headers_set = [] def set_app(self, application):
self.application = application def serve_forever(self):
listen_socket = self.listen_socket while True: # New client connection
self.client_connection, client_address = listen_socket.accept() # Handle one request and close the client connection. Then
# loop over to wait for another client connection
self.handle_one_request() def handle_one_request(self):
self.request_data = request_data = self.client_connection.recv(1024) # Print formatted request data a la 'curl -v'
print(''.join( '< {line}\n'.format(line=line) for line in request_data.splitlines()
))
self.parse_request(request_data) # Construct environment dictionary using request data
env = self.get_environ() # It's time to call our application callable and get
# back a result that will become HTTP response body
result = self.application(env, self.start_response) # Construct a response and send it back to the client
self.finish_response(result) def parse_request(self, text):
request_line = text.splitlines()[0]
request_line = request_line.rstrip('\r\n') # Break down the request line into components
(self.request_method, # GET
self.path, # /hello
self.request_version # HTTP/1.1
) = request_line.split() def get_environ(self):
env = {
} # The following code snippet does not follow PEP8 conventions
# but it's formatted the way it is for demonstration purposes
# to emphasize the required variables and their values
#
# Required WSGI variables
env['wsgi.version'] = (1, 0)
env['wsgi.url_scheme'] = 'http'
env['wsgi.input'] = StringIO.StringIO(self.request_data)
env['wsgi.errors'] = sys.stderr
env['wsgi.multithread'] = False
env['wsgi.multiprocess'] = False
env['wsgi.run_once'] = False
# Required CGI variables
env['REQUEST_METHOD'] = self.request_method # GET
env['PATH_INFO'] = self.path # /hello
env['SERVER_NAME'] = self.server_name # localhost
env['SERVER_PORT'] = str(self.server_port) # 8888
return env def start_response(self, status, response_headers, exc_info=None):
# Add necessary server headers
server_headers = [
('Date', 'Tue, 31 Mar 2015 12:54:48 GMT'),
('Server', 'WSGIServer 0.2'),
]
self.headers_set = [status, response_headers + server_headers] # To adhere to WSGI specification the start_response must return
# a 'write' callable. We simplicity's sake we'll ignore that detail
# for now.
# return self.finish_response
def finish_response(self, result):
try:
status, response_headers = self.headers_set
response = 'HTTP/1.1 {status}\r\n'.format(status=status) for header in response_headers:
response += '{0}: {1}\r\n'.format(*header)
response += '\r\n'
for data in result:
response += data # Print formatted response data a la 'curl -v'
print(''.join( '> {line}\n'.format(line=line) for line in response.splitlines()
))
self.client_connection.sendall(response) finally:
self.client_connection.close()
SERVER_ADDRESS = (HOST, PORT) = 'localhost', 8080def make_server(server_address, application):
server = WSGIServer(server_address)
server.set_app(application) return serverif __name__ == '__main__':
httpd = make_server(SERVER_ADDRESS, application)
print('WSGIServer: Serving HTTP on port {port} ...\n'.format(port=PORT))
httpd.serve_forever()复制代码
Of course, if you just write a server for development environment, you don't need to bother to make your own wheels, because the built-in python module provides the function of wsgi server.
from wsgiref.simple_server import make_server
srv = make_server('localhost', 8080, application)
srv.serve_forever()复制代码
As long as 3 lines of code can provide wsgi server, is it super convenient? Finally, I will visit and test the effect of a request initiated by the browser
The above is the introduction of wsgi. If you have a deep understanding of wsgi, you can be familiar with PEP333.
This article comes from the python video tutorial section of php Chinese website : https://www.php.cn/course/list/30.html