WSGI (Web Server Gateway Interface): Web service gateway interface, the interface between the server program and the application defined in the Python. In the development of

Web programs, it is generally divided into server programs and applications. The server program is responsible for encapsulating and sorting the data of the socket service, while the application is responsible for the logical processing of the Web request. The

Web application is essentially a socket server, and the user's browser is a socket client.

we use socket programming to achieve a simple Web server:

 import socket def handle_request (client): buf = client.recv (1024) print (buf) MSG = "HTTP/1.1 200 OKrnrn" #HTTP client.send (head of information ('%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 (

)

(main) in the above code, the function is the server function, handle_request () is the application. Here we use
wsgiref module Python to realize the above code like Web

 from wsgiref.simple_server import server: make_server def handle_request (Env, RES): res ("200 OK", "(" Content-Type "," text/html ") body =" < "); h1> Hello < /h1> World!"; return [body.encode ("UTF-8") if __name__ = = "__main__": httpd = make_server ("", 8000, handle_request) print ("Serving HTTP on port httpd.serve_forever (

) 80000)

above two copies of code to achieve the effect is the same, call the wsgiref module is reduced significantly the amount of code, the whole procedure is more simple. The
wsgiref module encapsulates the socket server's code, leaving only a calling interface, which saves the trouble of programmers. Programmers can focus on the logical processing of Web requests.

in the above code as an example, a detailed look at some key areas of wsgiref module source code:

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

1,

) entrance of the whole program is make_server (

 DEF) function: 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) # default class WSGIServer server.set_app (APP) # application the program, namely logic processing function to the return server 

2, make_server () function to generate a default WSGIServer Category:

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

WSGIServer, HTTPServer two class initialization function, call the parent class initialization function, TCPServer class __init__ () function extends BaseServer

class __init__ () function:

 class #BaseServer __init__ (DEF) function: __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 __init__ (DEF) function: __init__ (self, server_address, RequestHandle RClass, bind_and_activate=True): "Constructor. May be extended do not override." and "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 (except:) self.server_close (

) raise initialization function of the

TCPServer class is called server_bind (self, server_bind) (self) two:

 def server_bind function (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." and "self.socket.listen" (self.request_queue_size) 

(server.bind) can see the function call socket.bind () and server_activate () function, call socket.listen () function:

3, server.set_app (APP). The incoming Web request processing logic:

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

4 (httpd.serve_forever), call the BaseServer class function _handle_request_noblock () function to deal with multiple requests:

(self)

 def _handle_request_noblock: try: request, client_address = self.get_request (get_request) # (called socket.accep) (T) OSError: return if self.verify_request function except (request, client_address): try: self.process_request (request, client_address) except: 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 (call) socket.close (socket def finish_request) close (self, request, client_address): "Finish one request by instantiating RequestHandlerClass." and "self.RequestHandlerClass" (request, client_address, self) 

,

5 (process_request) calls finish_reque St () function, call the make_server function of the default parameters of WSGIRequestHandler class:

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

 # initialization function calls 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 (handle) call the WSGIRequestHandler class 

6,

after the initialization function is called () function to obtain the server logic 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) (finally: stdout.detach) logic function # here called server (

)

7, BaseHandler (handler.run) class function to perform the logic processing:

(self, application

 def run self.setup_environ (self.result): try:) = 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 HTTP request contains all information of the Dict
object self.sta Rt_response: a function that sends a HTTP response.

call in the application function,

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

]) that sends the head information of

HTTP response

8, BaseHandler class setup_environ () function to obtain the HTTP request header:

 def setup_environ (self the" Set "):" up the environment for one request "env = self.environ = self.os_environ.copy (os_environ=) (read_environ) (read_environ): def (read_environ) function:" Read environment fixing HTTP variables "enc sys.getfilesystemencoding (ESC) = try:''.encode ='surrogateescape'('utf-8', ESC) except LookupError: ESC ='replace'environ = Take the basic environment from # {} native-unicode os.environ. Attempt To fix the variables that # up 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_SOFTWARE',.Lower) # ') (On IIS, the HTTP request will be decoded as UTF-8 as long as input is a # the 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 enc # Oding, and MBCs is inherently unreliable (an MBCs string that to be valid # happens 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.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, BaseHandler start_response (

 DEF) function: start_response (self, status, headers, exc_info=None): "'start_response (as specified by)' callable PEP 3333 '" if exc_info: try " If: self.headers_sent: Re #


This concludes the body part