zoukankan      html  css  js  c++  java
  • Web框架的本质

    1. Web请求和响应的过程

    简单来说,服务端接收到用户访问网站的请求时,无非就是将用户发来的请求信息进行分析(请求头+请求体)。

    再根据用户请求信息中内容在服务端做对应的处理后,将处理后的结果(字符串)作为响应体,再加上响应头后构建成完整的响应报文返回给客户端。

    如我们可以根据请求头中的URL来加载对应的文件进行响应,而这个加载对应文件的过程我们可以做成一个函数,从而可以根据请求头中URL信息来执行不同的函数进行处理。

    而对于处理的过程,我们可以是直接加载一个html文件后,将整个html文件中的内容作为一个字符串加入响应体中后构建响应报文,再直接发送给客户端。这就是静态资源的请求过程。

    而对于变化的数据(动态资源),我们还需要从数据库中拿到对应的数据后,将这些数据填充进html文件中的指定位置,再将填充后的内容作为一个字符串附着进响应体中,再构建响应报文发送给客户端。

    这时,不难发现,现在的这个html文件,已然变成了一个模板,我们可以在这个模板上定义特殊的替换规则后,就可以填充我们想要添加的任何内容。这样就可以实现内容的动态显示。

    2. 一个简单的静态Web服务器

    根据以上基本原理,我们不难写出一个根据请求的URL来响应对应html网页内容的简单的静态资源web服务器。

    import socket
    
    def f1(request):
        # request中包含了用户请求的所有内容:请求头+请求体
        f = open('index.html', 'rb')
        data = f.read()
        f.close()
        return data
    
    def f2(request):
        f = open('article.html', 'rb')
        data = f.read()
        f.close()
        return data
    
    routers = [
        ('/f1', f1),
        ('/f2', f2),
    ]
    
    def run():
        sock = socket.socket()
        sock.bind(('127.0.0.1', 8080))
        sock.listen(5)
    
        while True:
            # 等待客户端来连接
            conn, addr = sock.accept()
            # 获取用户发送的数据,收到的数据是Bytes,(二进制格式)
            data = conn.recv(8096)
    
            """对用户发来的信息进行提取"""
    
            # 将内容转化成字符串类型
            data = str(data, encoding='utf-8')
            # data = bytes('shit', encoding='utf-8')
    
            # 将内容分割成请求头和请求体
            headers, bodys = data.split('
    
    ')
            # 得到请求头中的每一行数据
            temp_list = headers.split('
    ')
            # 对请求头中的第一行数据进行提取,取得请求方法、请求URL、请求方法
            method, url, protocol = temp_list[0].split(' ')
    
            """根据用户请求的URL来返回不同的内容"""
            """思路:
                遍历routers中的每个元组的第一个值和请求头中的url进行比较,
                若匹配成功,则将对应的函数名赋值给func_name,进而去执行该URL对应的函数
            """
            func_name = None
            for item in routers:
                if item[0] == url:
                    func_name = item[1]
                    break
            if func_name:
                response = func_name(data)  # 把data中的内容传进去
            else:
                response = b"404 not found"
    
            conn.send(response)
            conn.close()
    
    
    if __name__ == '__main__':
            run()

    3. 动态网站Web服务器

    动态web无非就是数据从数据库来提取,所以数据是会变化的,而非像静态页面那样一成不变。

    import socket
    import pymysql
    
    # 静态页面
    def index(request):
        # request中包含了用户请求的所有内容:请求头+请求体
        f = open('index.html', 'rb')
        data = f.read()
        f.close()
        return data
    
    # 静态页面
    def article(request):
        f = open('article.html', 'rb')
        data = f.read()
        f.close()
        return data
    
    # 动态页面
    def user_info(request):
    
        # 连接数据库并取得数据
        mysql_conn = pymysql.connect(host='10.0.0.204', port=3306, user='hgzero', passwd='woshiniba', db='my_test')
        conn_cursor = mysql_conn.cursor(cursor=pymysql.cursors.DictCursor)
        ret = conn_cursor.execute("select name,age,gender from first_test")
        print("受影响的行数:%s" % ret)
        user_list = conn_cursor.fetchall()
        conn_cursor.close()
        mysql_conn.close()
        print("打印从数据库中拿到的内容: %s" % user_list)
    
        # 将从数据库中拿到的内容进行拼接
        content_list = []
        for row in user_list:
            tp = "<tr><th>%s</th><th>%s</th><th>%s</th></tr>" % (row["name"], row["age"], row["gender"])
            content_list.append(tp)
        user_content = "".join(content_list)
    
        # 将html文件中指定位置的内容替换成数据库中取得后拼接好的内容
        f = open("user_list.html", "r", encoding='utf-8')
        html_template = f.read()
        f.close()
    
        # 替换为指定内容
        # 这里其实就是最简单的所谓的模板的渲染
        data = html_template.replace("@@content@@", user_content)
    
        return bytes(data, encoding="utf-8")
    
    
    routers = [
        ('/index.html', index),
        ('/article.html', article),
        ('/user_info.html', user_info),
    ]
    
    def run():
        sock = socket.socket()
        sock.bind(('127.0.0.1', 8080))
        sock.listen(5)
    
        while True:
            # 等待客户端来连接
            conn, addr = sock.accept()
            # 获取用户发送的数据,收到的数据是Bytes,(二进制格式)
            data = conn.recv(8096)
    
            """对用户发来的信息进行提取"""
    
            # 将内容转化成字符串类型
            data = str(data, encoding='utf-8')
            # data = bytes('shit', encoding='utf-8')
    
            # 将内容分割成请求头和请求体
            headers, bodys = data.split('
    
    ')
            # 得到请求头中的每一行数据
            temp_list = headers.split('
    ')
            # 对请求头中的第一行数据进行提取,取得请求方法、请求URL、请求方法
            method, url, protocol = temp_list[0].split(' ')
    
            """根据用户请求的URL来返回不同的内容"""
            """思路:
                遍历routers中的每个元组的第一个值和请求头中的url进行比较,
                若匹配成功,则将对应的函数名赋值给func_name,进而去执行该URL对应的函数
            """
            func_name = None
            for item in routers:
                if item[0] == url:
                    func_name = item[1]
                    break
            if func_name:
                response = func_name(data)  # 把data中的内容传进去
            else:
                response = b"404 not found"
    
            conn.send(response)
            conn.close()
    
    
    if __name__ == '__main__':
            run()
    

    4. 用Jinja2进行模板渲染

    这时不难发现,如果我们手动的对html模板进行内容替换,这将会非常麻烦,然而已经有这样的模板渲染工具了。我们可以按照Jinja2规定要的语法来对我们的html模板进行渲染。

    import socket
    import pymysql
    
    # 静态页面
    def index(request):
        # request中包含了用户请求的所有内容:请求头+请求体
        f = open('index.html', 'rb')
        data = f.read()
        f.close()
        return data
    
    # 静态页面
    def article(request):
        f = open('article.html', 'rb')
        data = f.read()
        f.close()
        return data
    
    # 动态页面,手动渲染
    def user_info(request):
    
        # 连接数据库并取得数据
        mysql_conn = pymysql.connect(host='10.0.0.204', port=3306, user='hgzero', passwd='woshiniba', db='my_test')
        conn_cursor = mysql_conn.cursor(cursor=pymysql.cursors.DictCursor)
        ret = conn_cursor.execute("select name,age,gender from first_test")
        print("受影响的行数:%s" % ret)
        user_list = conn_cursor.fetchall()
        conn_cursor.close()
        mysql_conn.close()
        print("打印从数据库中拿到的内容: %s" % user_list)
    
        # 将从数据库中拿到的内容进行拼接
        content_list = []
        for row in user_list:
            tp = "<tr><th>%s</th><th>%s</th><th>%s</th></tr>" % (row["name"], row["age"], row["gender"])
            content_list.append(tp)
        user_content = "".join(content_list)
    
        # 将html文件中指定位置的内容替换成数据库中取得后拼接好的内容
        f = open("template_shit.html", "r", encoding='utf-8')
        html_template = f.read()
        f.close()
    
        # 替换为指定内容
        # 这里其实就是最简单的所谓的模板的渲染
        data = html_template.replace("@@content@@", user_content)
    
        return bytes(data, encoding="utf-8")
    
    # 动态页面,用jinja2进行模板渲染
    def template_shit(request):
        # 连接数据库并取得数据
        mysql_conn = pymysql.connect(host='10.0.0.204', port=3306, user='hgzero', passwd='woshiniba', db='my_test')
        conn_cursor = mysql_conn.cursor(cursor=pymysql.cursors.DictCursor)
        conn_cursor.execute("select name,age,gender from first_test")
        user_list = conn_cursor.fetchall()
        conn_cursor.close()
        mysql_conn.close()
    
        # 获取html模板的内容
        f = open("template_shit.html", "r", encoding='utf-8')
        html_data = f.read()
        f.close()
    
        # 用jinja2进行模板渲染
        from jinja2 import Template
        template = Template(html_data)
        # 用从数据库中拿到的user_list来替换模板中的user_list变量
        data = template.render(user_list=user_list)
        # 模板中定义的规则:
        """{% for rwo in user_list %}
                      <tr>
                          <td>{{row.name}}</td>
                          <td>{{row.age}}</td>
                          <td>{{row.gender}}</td>
                      </tr>
                  {% endfor %}
        """
        print(data)  # 看看模板生成的内容
        return data.encode("utf-8")
    
    
    routers = [
        ('/index.html', index),
        ('/article.html', article),
        ('/user_info.html', user_info),
        ('/template_shit.html', template_shit),
    ]
    
    def run():
        sock = socket.socket()
        sock.bind(('127.0.0.1', 8080))
        sock.listen(5)
    
        while True:
            # 等待客户端来连接
            conn, addr = sock.accept()
            # 获取用户发送的数据,收到的数据是Bytes,(二进制格式)
            data = conn.recv(8096)
    
            """对用户发来的信息进行提取"""
    
            # 将内容转化成字符串类型
            data = str(data, encoding='utf-8')
            # data = bytes('shit', encoding='utf-8')
    
            # 将内容分割成请求头和请求体
            headers, bodys = data.split('
    
    ')
            # 得到请求头中的每一行数据
            temp_list = headers.split('
    ')
            # 对请求头中的第一行数据进行提取,取得请求方法、请求URL、请求方法
            method, url, protocol = temp_list[0].split(' ')
    
            """根据用户请求的URL来返回不同的内容"""
            """思路:
                遍历routers中的每个元组的第一个值和请求头中的url进行比较,
                若匹配成功,则将对应的函数名赋值给func_name,进而去执行该URL对应的函数
            """
            func_name = None
            for item in routers:
                if item[0] == url:
                    func_name = item[1]
                    break
            if func_name:
                response = func_name(data)  # 把data中的内容传进去
            else:
                response = b"404 not found"
    
            conn.send(response)
            conn.close()
    
    
    if __name__ == '__main__':
            run()
    

    至此,可以看到,现在它已经基本上实现的一个框架应该实现的功能。

    5. Web框架的种类

    5.1 Web框架应该实现的功能

    1. Socket服务端
    2. 路由系统:根据URL来返回不同的内容,URL --> 函数
    3. 字符串加入响应体返回给用户:模板引擎渲染,字符串

    5.2 Web框架的种类

    根据以上的三种主要功能,web框架可以分为以下几类

    • 自己实现了 1,2,3  
      • Tornado
    • 实现了 2,3 ,而使用了第三方的Socket服务端
      • Django
    • 实现了 2 , 而使用了第三方的Socket服务器以及第三方的模板渲染引擎(如Jinja2)
      • flask

  • 相关阅读:
    11.正则表达式的一些简单应用
    10.JavaScript距离生日还有多少天、根据出生年月日计算年龄、打印当前月份每天的星期
    9.JavaScript获取当前时间,返回格式年-月-日 时:分:秒
    8.JavaScript获取一个从最小值到最大值的随机数
    7.JavaScript数组乱序排序
    6.JavaScript中的new.target
    5.JavaScript自定义数组排序
    2-9 随机模块
    2-8 四则运算
    1-22Python练习题1-1
  • 原文地址:https://www.cnblogs.com/hgzero/p/13216511.html
Copyright © 2011-2022 走看看