diy simple web architecture using wsgiref Library

1. Understand CGI and WSGI

(1)CGI

CGI (Common Gateway Interface) is a general gateway interface, that is, the interface protocol. The front end sends a URL (carrying request type, parameters, cookie s and other information) request to the server. The server writes various parameters of the request into the process environment variables, such as REQUEST_METHOD,PATH_INFO, and then start the CGI module and send it to the CGI program, CGI program (which can be written in various languages, such as C, C + +, VB and Delphi) parses various parameters from environment variables, and then outputs the content to standard output (for example, cout a piece of HTML code). These contents are not printed on the console, but finally respond to your browser and render the web page. Every time you send a request to CGI, a CGI process will be generated. This is the so-called fork and exec mode, which is often the crux of the concurrency bottleneck. Reverse proxy and large distributed systems can be used to a certain extent Reduce these pressures to a certain extent.

(2)WSGI

WSGI (Python Web Server Gateway Interface, abbreviated as WSGI) is a web server gateway interface, which is also an interface protocol. The front end sends a URL to the server (carrying request type, parameters, cookie s and other information) request. The server passes various parameters of the request to the WSGI module. WSGI pythonizes various parameters, encapsulates them as request objects, passes them to the WSGI Application registered according to the WSGI interface standard, and returns the response parameter to the client.

2. Introduction to wsgiref Library

Wsgiref is a python built-in library that implements a simple WSGI Server and WSGI Application. Using this library, we can easily implement a custom web architecture without considering the TCP/HTTP layer protocol. The source code of the library is located in the / django/lib/wsgiref folder. The library provides five modules:

* util -- Miscellaneous useful functions and wrappers

* headers -- Manage response headers

* handlers -- base classes for server/gateway implementations

* simple_server -- a simple BaseHTTPServer that supports WSGI

* validate -- validation wrapper that sits between an app and a server
                  to detect errors in either

The following is mainly about simple_ The key functions and usage of the server module are described

3. wsgiref.simple_server class usage and partial source code analysis

(1) Let's start with the previous code

The code comes from simple_ server. Last 7 lines of PY

if __name__ == '__main__':
    with make_server('', 8000, demo_app) as httpd:
        sa = httpd.socket.getsockname()
        print("Serving HTTP on", sa[0], "port", sa[1], "...")
        import webbrowser
        webbrowser.open('http://localhost:8000/xyz?abc')
        httpd.handle_request()  # serve one request, then exit

This code expresses two meanings: start the service - > process‘ http://localhost:8000/xyz?abc 'request

(2) Analyze the service startup process of make_server

  server_class passes in two parameters, The first tuple (host,ip), the second WSGIRequestHandler class, the first parameter is used to start the service of socketserver.TCPServer (Mark 1 in the figure), and the second parameter WSGIRequestHandler is used to initialize the self.RequestHandlerClass attribute of BaseServer class (Mark 2 in the figure), which is used to initialize the object with the finish_request() function (Mark 3 in the figure), the main purpose is to realize the subsequent callback function call

(3) Analyze the process of handle_request() function

The implementation process of this function is in the base class BaseServer. This function mainly implements the following functions (epoll asynchronous concurrency is not discussed here. Please refer to my previous blog for relevant epoll contents):

  get_request()—->verify_request()—->process_request()—->shutdown_request()

Just look at the function name to understand the whole process

(4) Now it's time to focus. Let's see how the demo_app callback is implemented

Next, we mainly analyze make_ The third parameter demo of the server() function_ How does app implement the call

Through the source code, we can see that finish_ RequestHandlerClass initialization is implemented in the request () function, that is, WSGIRequestHandler initialization

def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)

Take a picture and you can see everything clearly

a. after the service is started, WSGIServer passes set_app saves the callback function

  b. finish_request() instantiates WSGIRequestHandler and calls the constructor of its base class BaseRequestHandle. The constructor also calls the handle processing function. Since the derived class WSGIRequestHandler rewrites the handle method, it actually calls the handle function of WSGIRequestHandler class. As shown in Figure 3 above, get the callback function object and execute it.

def run(self, application):
        try:
            self.setup_environ()
            self.result = application(self.environ, self.start_response)
            self.finish_response()
            . . . . . . . . . . . . . . 

So far, everything is clear! Next, you can freely process the callback function!

4. DIY web Architecture

Imitate the model - > route - > View - > template model of django architecture to realize http requests and display web pages

(1)models.py

Use redis to create two string structures, name and url

import redis

class Model:
    def __init__(self):
        conn = redis.Redis()
        self.name = conn.get('name')
        self.url = conn.get('url')

(2)urls.py

import views

urlpattern = ((r'/fate0729/', views.login),)

(3)views.py

Realize the rendering of the template through the model

from models import Model
import re

def render(html_path, **wargvs):
    with open(html_path, 'r') as pf:
        data = ''.join(pf.readlines())
        print(data)

    if wargvs is not None:
        # For testing purposes, the fixed format obj. Is used here attr
        results = re.findall(r'{{(.*)}}', data)
        for result in results:
            obj_attr_list = result.partition('.')
            obj = wargvs.get(obj_attr_list[0])
            attr = obj_attr_list[-1]
            regex = r'{{.*\.%s}}' %(attr)
            value = getattr(obj,attr).decode('utf-8')
            print(attr,value)
            data = re.sub(regex,str(value), data)
    return data.encode('utf-8')

def login(request):
    model = Model()
    return render('web.html', **{'model':model})

(4)main.py

from wsgiref.simple_server import make_server
import urls

def routers():
    urlpattern=urls.urlpattern
    return urlpattern

def applications(environ,start_response):
    path=environ.get("PATH_INFO")
    start_response('200 OK', [('Content-Type', 'text/html'),('Charset', 'utf8')])

    urlpattern=routers()
    func=None
    for item in urlpattern:
        if path==item[0]:
            func=item[1]
            break
    if func:
        return [func(environ)]
    else:
        return [b"<h1>404!<h1>"]

if __name__ == '__main__':
    conn = make_server('127.0.0.1', 8001, applications)
    print('server is working...')
    conn.serve_forever()

(5) Testing

  python main.py

Open the browser and enter: 127.0 0.1/fate0729/

Publisher: full stack programmer, stack length, please indicate the source for Reprint: https://javaforall.cn/120042.html Original link: https://javaforall.cn

Added by Nikos7 on Mon, 03 Jan 2022 09:06:51 +0200