Detailed description of the use of Python WSGI and pythonwsgi

Source: Internet
Author: User

Detailed description of the use of Python WSGI and pythonwsgi

WSGI (Web Server Gateway Interface): an Interface between a Server program and an application defined in Python.

Web programs are generally divided into server programs and applications. The server program encapsulates and organizes the data of the socket service, and the application program is responsible for logical processing of Web requests.

A Web application is essentially a socket server, and a user's browser is a socket Client.

We first use socket programming to implement a simple Web Server:

Import socket def handle_request (client): buf = client. recv (1024) print (buf) msg = "HTTP/1.1 200 OK \ r \ n" # HTTP header information client. send ('% s' % msg ). encode () msg = "Hello, World! "Client. send ('% s' % msg ). encode () def main (): ip_port = ("localhost", 8000) sock = socket. socket (socket. AF_INET, socket. SOCK_STREAM) sock. bind (ip_port) sock. listen (5) while True: conn, addr = sock. accept () handle_request (conn) conn. close () if _ name _ = "_ main _": main ()

In the above Code, the main () function is the server function, and handle_request () is the application program.
The following uses the python wsgiref module to implement the same Web server as the above Code:

from wsgiref.simple_server import make_server  def handle_request(env, res):   res("200 OK",[("Content-Type","text/html")])   body = "

The above two pieces of code achieve the same effect. Calling the wsgiref module significantly saves the amount of code, making the entire program more concise.
The wsgiref module encapsulates the code of the socket server, leaving only one called interface, saving the programmer's trouble. The programmer can focus on the logic processing of Web requests.

The above code is used as an example. Let's take a closer look at some of the key points in the source code of the wsgiref module:

if __name__ == "__main__":   httpd = make_server("",8000,handle_request)   print("Serving http on port 80000")   httpd.serve_forever() 

1. The entire program entry is the make_server () function:

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) # A WSGIServer type server is created by default. set_app (app) # send the application, that is, the logic processing function, to the return server class.

2. The make_server () function generates a WSGIServer class by default:

Class WSGIServer (HTTPServer ):
Class HTTPServer (socketserver. TCPServer ):
Class TCPServer (BaseServer ):

WSGIServer and HTTPServer do not have initialization functions. They call the initialization functions of the parent class. The _ init _ () function of the TCPServer class extends the BaseServer

The _ init _ () function of the class:

# BaseServer class _ init _ () function: def _ init _ (self, server_address, RequestHandlerClass): "" Constructor. may be extended, do not override. "self. server_address = server_address self. requestHandlerClass = RequestHandlerClass self. _ is_shut_down = threading. event () self. _ shutdown_request = False
# TCPServer class _ init _ () function: def _ init _ (self, server_address, RequestHandlerClass, bind_and_activate = True): "" Constructor. may be extended, do not override. "BaseServer. _ init _ (self, server_address, RequestHandlerClass) self. socket = socket. socket (self. address_family, self. socket_type) if bind_and_activate: try: self. server_bind () self. server_activate () failed T: self. server_close () raise

The initialization function of the TCPServer class also calls the server_bind (self) and server_bind (self) functions:

def server_bind(self):   """Called by constructor to bind the socket.May be overridden."""   if self.allow_reuse_address:     self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)   self.socket.bind(self.server_address)   self.server_address = self.socket.getsockname()  def self.server_activate(self):   """Called by constructor to activate the server.May be overridden."""   self.socket.listen(self.request_queue_size)  

The server. bind () function calls the socket. bind () function, while server_activate () calls the socket. listen () function:

3. server. set_app (app), which is used to pass in the processing logic of Web requests:

def set_app(self,application):   self.application = application 

4. The httpd. serve_forever () function calls the _ handle_request_noblock () function of the BaseServer class to process multiple requests:

Def _ handle_request_noblock (self): try: request, client_address = self. get_request () # get_request () calls socket. accept () function doesn't OSError: return if self. verify_request (request, client_address): try: self. process_request (request, client_address) handle T: self. handle_error (request, client_address) self. shutdown_request (request) else: self. shutdown_request (request)
Def process_request (self, request, client_address): self. finish_request (request, client_address) self. shutdown_request (request) # shutdown_request () calls socket. close () close socket def finish_request (self, request, client_address): "" Finish one request by instantiating RequestHandlerClass. "self. requestHandlerClass (request, client_address, self)

5. The process_request () function calls the finish_request () function. The default parameter WSGIRequestHandler class that calls the make_server function is described as follows:

Class WSGIRequestHandler (BaseHTTPRequestHandler ):
Class BaseHTTPRequestHandler (socketserver. StreamRequestHandler ):
Class StreamRequestHandler (BaseRequestHandler ):

# Call the initialization function of the BaseRequestHandler class: def _ init _ (self, request, client_address, server): self. request = request self. client_address = client_address self. server = server self. setup () try: self. handle () finally: self. finish ()

6. After the initialization function is called, call the handle () function of the WSGIRequestHandler class to obtain the server's logical processing function:

Def handle (self): "" Handle a single HTTP request "" try: handler = ServerHandler (self. rfile, stdout, self. get_stderr (), self. get_environ () handler. request_handler = self # backpointer for logging handler. run (self. server. get_app () # Call the server's logical processing function finally: stdout. detach ()

7. BaseHandler class handler. run () function execution logic processing:

def run(self, application):    try:     self.setup_environ()     self.result = application(self.environ, self.start_response)     self.finish_response()   except:     try:       self.handle_error()     except:       self.close()       raise  # ...and let the actual server figure it out. 

Self. environ: A dict object containing all HTTP Request Information
Self. start_response: a function that sends an HTTP response.

In the application function, call:

res("200 OK",[("Content-Type","text/html")]) 

In this way, the HTTP response header is sent.

8. The setup_environ () function of the BaseHandler class obtains the header information of the HTTP request:

Def setup_environ (self): "" Set up the environment for one request "" env = self. environ = self. OS _environ.copy () OS _environ = read_environ () function: def read_environ (): "" Read environment, fixing HTTP variables "enc = sys. getfilesystemencoding () esc = 'surrogateescape 'try :''. encode ('utf-8', esc) failed t LookupError: esc = 'replace 'environ = {}# Take the basic environment from native-unicode OS. environ. attempt to # fix up the variables that come from the HTTP request to compensate for # the bytes-> unicode decoding step that will already have taken place. for k, v in OS. environ. items (): if _ needs_transcode (k): # On win32, the OS. environ is natively Unicode. different servers # decode the request bytes using different encodings. if sys. platform = 'win32 ': software = OS. environ. get ('server _ soft ',''). lower () # On IIS, the HTTP request will be decoded as UTF-8 long # as the input is a valid UTF-8 sequence. otherwise it is # decoded using the system code page (mbcs), with no way to # detect this has happened. because UTF-8 is the more likely # encoding, and mbcs is inherently unreliable (an mbcs string # that happens to be valid UTF-8 will not be decoded as mbcs) # always recreate the original bytes as UTF-8. if software. startswith ('Microsoft-iis/'): v = v. encode ('utf-8 '). decode ('iso-8859-1 ') # Apache mod_cgi writes bytes-as-unicode (as if ISO-8859-1) direct # to the Unicode environ. no modification needed. elif software. startswith ('apache/'): pass # Python 3's http. server. CGIHTTPRequestHandler decodes # using the urllib. the unquote default of UTF-8, amongst other # issues. elif (software. startswith ('simplehttp/') and 'python/3' in software): v = v. encode ('utf-8 '). decode ('iso-8859-1 ') # For other servers, guess that they have written bytes to # the environ using stdio byte-oriented interfaces, ending up # with the system code page. else: v = v. encode (enc, 'replace '). decode ('iso-8859-1 ') # Recover bytes from unicode environ, using surrogate escapes # where available (Python 3.1 + ). else: v = v. encode (enc, esc ). decode ('iso-8859-1 ') environ [k] = v return environ

9. start_response () function of BaseHandler class:

def start_response(self, status, headers,exc_info=None):   """'start_response()' callable as specified by PEP 3333"""   if exc_info:     try:       if self.headers_sent:         # Re-raise original exception if headers sent         raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])     finally:       exc_info = None    # avoid dangling circular ref   elif self.headers is not None:     raise AssertionError("Headers already set!")    self.status = status   self.headers = self.headers_class(headers)   status = self._convert_string_type(status, "Status")   assert len(status)>=4,"Status must be at least 4 characters"   assert status[:3].isdigit(), "Status message must begin w/3-digit code"   assert status[3]==" ", "Status message must have a space after code"    if __debug__:     for name, val in headers:       name = self._convert_string_type(name, "Header name")       val = self._convert_string_type(val, "Header value")     return self.write 

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

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.