Handwriting Lite web framework

Web framework

Web application framework (Web application framework) is a development framework to support the development of dynamic web sites, web applications and network services. Web application framework helps to reduce the workload of the development activities of the commonality of the page, for example, many frameworks provide database access interface, the standard model, and session management, etc., can improve the reusability of code.

Python web framework comparison

The following three types of common Python web framework brief:

Django

Python framework Django has become one of the most widely deployed for creating Web applications. Django comes with most of the components may be required, therefore it tends to build large applications instead of small applications.
Django's socket using a wsgiref module, routing and view functions, templates are rendered his writing.

Flask

Most of the discussion of Python Web frameworks are from Flask mentioned at the beginning. Flask is a mature, easy to understand framework, widely used and very stable, dapper, built-in function modules are extremely rare, most of them are dependent on third-party modules.
Flask of the socket using a wsgiref module, routing and view their function is written, template rendering using a third-party modules jinjia2.

Tornado

Tornado is specific for the small frame with another embodiment, the asynchronous natural, powerful performance. Tornado designed for building asynchronous web applications and design, ideal for open simultaneously create a large number of network connections and services to keep it alive, that relate to any content WebSockets or long polling.
socket, routing and view function, template rendering are their own.

Web framework nature

Web application is essentially a socket server, and the user's browser is a client socket. So that we can follow the HTTP protocol to implement a simple version of a Web framework.

import socket
server = socket.socket()  # 不传参数默认就是TCP协议
server.bind(('127.0.0.1',8080)) # 绑定IP和端口
server.listen(5)

while True:
    conn, addr = server.accept()  # 阻塞 等待客户端链接
    data = conn.recv(1024)
    # 因为要遵循HTTP协议,所以回复的消息也要加状态行
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    # 手动处理http数据获取用户访问的路径,url是我们从浏览器发过来的消息中分离出的访问路径
    current_path = data.decode('utf-8').split('\r\n')[0].split(' ')[1]
    if current_path == '/index':
        # 路由匹配上之后返回index
        # conn.send(b'<h1>index</h1>')
        with open('index.html','rb') as f:
            # TCP对于发送间隔时间较短和较少的内容会一次发送过去
            conn.send(f.read())
    else:
        # 当匹配不上的时候统一返回404
        conn.send(b'404 not found!')
    conn.close()

This page can be displayed, but are static ah. Content of the page will not change, I want a dynamic website.

import socket
import time
sk = socket.socket()
sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
sk.listen(5)  # 监听
# 将返回不同的内容部分封装成函数
def index(url):
    with open("index.html", "r", encoding="utf8") as f:
        s = f.read()
        now = time.strftime('%Y-%m-%d %X')
        res = s.replace("@@time@@", now)  # 在网页中定义好特殊符号,用动态的数据去替换提前定义好的特殊符号
    return res
def home(url):
    with open("home.html", "r", encoding="utf8") as f:
        res = f.read()
    return res
# 定义一个url和实际要执行的函数的对应关系
list1 = [
    ("/index", index),
    ("/home", home),
]
while True:
    # 等待连接
    conn, add = sk.accept()
    data = conn.recv(8096)  # 接收客户端发来的消息
    # 从data中取到路径
    data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
    # 按\r\n分割
    data1 = data.split("\r\n")[0]
    url = data1.split(" ")[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
    # 根据不同的路径返回不同内容
    func = None  # 定义一个保存将要执行的函数名的变量
    for i in list1:
        if i[0] == url:
            func = i[1]
            break
    if func:
        response = func(url)
    else:
        response = "404 not found!"
    # 返回具体的响应消息
    conn.send(response.encode('utf-8'))
    conn.close()

WSGI

PythonWeb Server Gateway Interface (Python Web Server Gateway Interface, abbreviated as WSGI) is an interface between the framework and Python applications or Web servers, it has been widely accepted, it has basically reached its goal of portability. WSGI no official implementation, because more like a WSGI protocol. As long as compliance with these agreements, WSGI application (Application) can be run on any server (Server).

wsgiref module

The simplest Web application is the first HTML file is saved with the good, with an existing HTTP server software, the user receives the request, reads from the HTML file and returns. If you want to dynamically generate HTML, you need to put these steps to achieve their own. However, acceptance of the HTTP request, parse HTTP request, the HTTP response is sent coolies live, by your own to achieve is a waste of time and effort. Because we do not want access to TCP connections, HTTP request and response format of the original, so the need for a unified interface to implement such a protocol server software, let us concentrate on writing Web services using Python. This interface is WSGI: Web Server Gateway Interface. The wsgiref python module is developed based on wsgi protocol service module.

We use wsgiref module to replace our own web framework written socket server part:

from wsgiref.simple_server import make_server
import time

def index(env):
    with open("index.html", "r", encoding="utf8") as f:
        s = f.read()
        now = time.strftime('%Y-%m-%d %X')
        res = s.replace("@@time@@", now)  # 在网页中定义好特殊符号,用动态的数据去替换提前定义好的特殊符号
    return res
def home(env):
    with open("home.html", "r", encoding="utf8") as f:
        res = f.read()
    return res

def error(env):
    return '404 error'

urls = [
    ('/index',index),
    ('/home',home),
]

def run(env,response):
    '''
    :param env:请求相关的信息
    :param response:响应相关的信息
    :return:
    '''
    response('200 OK',[('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息
    # env是一个大字典 里面装了一堆处理好了的键值对数据
    url = env.get('PATH_INFO') # 取到用户输入的url
    func = None
    for url_map in urls:
        if url == url_map[0]:
            func = url_map[1]
            break
    if func:
        res = func(env)
    else:
        res = error(env)
    return [res.encode('utf-8')]

if __name__ == '__main__':
    server = make_server('127.0.0.1',8080,run)
    server.serve_forever()

jinja2

The above code implements a simple dynamic, I can query data from the database, and then I went to replace the corresponding content in html, and then sent to the browser finished rendering. This process is equivalent to HTML template rendering data. It is essentially to replace the data to show HTML content to use some special symbols. In fact, there is a ready-made template rendering tools:jinja2

jinja2 Flask is a template system developed by the authors, was originally a template engine imitation django template, templates provide support for the Flask, because of its flexible, fast and safe, etc. are widely used. jinja2 Enviroment module called a class, instances of this class used to store configuration and global objects, and then load the file from the template system or other location.

jinja2 reason is widely used because it has the following advantages:

    1. With respect to the Template, jinja2 more flexible, which provides control structure, expression and inheritance.
    2. Only with respect to the control structure Mako, jinja2, not allowed to write a lot of business logic in the template.
    3. With respect to the Django template, jinja2 better performance.
    4. Readability great Jinja2 template.

installation

Since jinja2 belong to third-party modules, you first need to install it

pip3 install jinja2

Use jinja2 render html file:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <table class="table table-hover table-striped table-bordered">
                <thead>
                    <tr>
                        <th>id</th>
                        <th>name</th>
                        <th>password</th>
                    </tr>
                </thead>
                <tbody>
                    {% for user in user_dict %}  <!--[{},{},{},{}]-->
                        <tr>
                            <td>{{ user.id }}</td>
                            <td>{{ user.name }}</td>
                            <td>{{ user.password }}</td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>

py Code

from wsgiref.simple_server import make_server
from jinja2 import Template
import pymysql

def index(env):
    # 连接数据库 获取数据 渲染到前端页面
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = 'mysql',
        database = 'jinja',
        charset = 'utf8',
        autocommit = True
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    cursor.execute('select * from userifo')
    user_dict= cursor.fetchall()  # [{},{},{},{}]
    with open(r'templates/index.html','r',encoding='utf-8') as f:
        data = f.read()
    tmp = Template(data)
    return tmp.render(user_dict=user_dict)

def error(env):
    return '404 error'
    
urls = [
    ('/index',index),
]

def run(env,response):
    '''
    :param env:请求相关的信息
    :param response:响应相关的信息
    :return:
    '''
    response('200 OK',[('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息
    # env是一个大字典 里面装了一堆处理好了的键值对数据
    url = env.get('PATH_INFO') # 取到用户输入的url
    func = None
    for url_map in urls:
        if url == url_map[0]:
            func = url_map[1]
            break
    if func:
        res = func(env)
    else:
        res = error(env)
    return [res.encode('utf-8')]

if __name__ == '__main__':
    server = make_server('127.0.0.1',8080,run)
    server.serve_forever()

Guess you like

Origin blog.csdn.net/linwow/article/details/90921053