自己动手写出静态网站与动态网站

1.简介

web框架的本质:socket服务端与浏览器的通信
socket服务端功能划分:
1.负责与浏览器收发消息(socket通信) --》wsgiref/uWsgi/gunicorn等web服务网关接口和服务器
2.根据用户访问不同的路径执行不同的函数 --》路由系统(url与函数的对应关系)
3.从HTML读取出内容并且完成字符串的替换 --》jinja2(模板语言)

2.静态网站

"""
这是一个静态的web网站,返回什么数据类型就是什么,而现在网站都是动态的。
"""
import socket


def f1(request):
    """
    处理用户请求,并返回相应的内容
    :param request: 用户请求的所有信息
    :return:
    """
    # 读取本地二进制文件并返回(在这里是自己写模板,可以任意后缀名文件并不一定需要html后缀)
    f = open('index.fsw','rb')
    data = f.read()
    f.close()
    return data

def f2(request):
    f = open('aricle.tpl','rb')
    data = f.read()
    f.close()
    return data

# 路由与函数的对应关系(路由系统)
routers = [
    ('/xxx', f1),
    ('/ooo', f2),
]


def run():
    # 获取socket对象
    sock = socket.socket()
    # 绑定ip地址和端口
    sock.bind(('127.0.0.1',8080))
    # 开始监听(设置最大监听数5个)
    sock.listen(5)

    while True:
        conn,addr = sock.accept() # 夯住,等待用户连接
        # 获取用户发送的数据
        data = conn.recv(8096)
        # 直接转换为字符串
        data = str(data,encoding='utf-8')
        print(data)
        # 根据http协议划分请求头和请求体


        headers,bodys = data.split('

')
        # 根据已有的http协议数据结构切分元素
        temp_list = headers.split('
')
        # 分别获取请求方法、请求url地址、请求协议类型
        method,url,protocal = temp_list[0].split(' ')
        conn.send(b"HTTP/1.1 200 OK

")

        func_name = None    # 设置标志位
        for item in routers:
            # 遍历url与函数对应关系表,并判断当前请求url是否相等
            if item[0] == url:
                # 能对应就获取函数名并停止循环
                func_name = item[1]
                break

        if func_name:
            # 有这个函数就加括号调用并传入参数
            response = func_name(data)
        else:
            response = b"404"
        # 返回函数处理后的结果
        conn.send(response)
        conn.close()

if __name__ == '__main__':
    run()
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <table border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <th>1</th>
                <th>root</th>
                <th>root@qq.com</th>
            </tr>
        </tbody>
    </table>
</body>
</html>
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>用户登录</h1>
    <form>
        <p><input type="text" placeholder="用户名" /></p>
        <p><input type="password" placeholder="密码" /></p>
    </form>
</body>
</html>
View Code

3.动态网站

"""动态网站则是在静态网站的基础之上,进行字符串的替换,以完成网站页面的实时更新效果"""
import socket

def f1(request):
    """
    处理用户请求,并返回相应的内容
    :param request: 用户请求的所有信息
    :return:
    """
    f = open('index.fsw','rb')
    data = f.read()
    f.close()
    return data

def f2(request):
    """
    运用时间戳的方式,初步实现动态网站
    :param request:
    :return:
    """
    f = open('aricle.tpl','r',encoding='utf-8')
    data = f.read()
    f.close()
    import time
    # 获取时间戳
    ctime = time.time()
    # 调用字符串的replace()替换方法换成时间戳,页面每次刷新显示的数据都不一样
    data = data.replace('@@sw@@',str(ctime))
    # 返回bytes()类型数据
    return bytes(data,encoding='utf-8')

def f3(request):
    """
    获取数据库数据,只要数据库数据有更新,则页面刷新之后都会显示
    :param request: 用户请求的信息
    :return:
    """
    import pymysql

    # 创建连接对象
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='yang123', db='yangyu')
    # 获取游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql语句查询数据库数据
    cursor.execute("select id,username,password from userinfo")
    # 获取表中所有数据
    user_list = cursor.fetchall()
    # 关闭游标对象
    cursor.close()
    # 关闭连接对象
    conn.close()

    content_list = []
    for row in user_list:
        # 遍历数据库查询的数据,拼接字符串
        tp = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" %(row['id'],row['username'],row['password'])
        # 把拼接的字符串添加到列表
        content_list.append(tp)
    # 调用.join方法把列表转换为字符串
    content = "".join(content_list)


    f = open('userlist.html','r',encoding='utf-8')
    template = f.read()
    f.close()

    # 模板渲染(模板+数据)完成字符串的替换
    data = template.replace('@@sdfsdffd@@',content)
    return bytes(data,encoding='utf-8')

def f4(request):
    """
    调用第三方模块,实现页面模板的渲染
    :param request:
    :return:
    """
    import pymysql

    # 创建连接对象
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='yang123', db='yangyu')
    # 获取游标
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行sql语句查询数据库数据
    cursor.execute("select id,username,password from userinfo")
    # 获取表中所有数据
    user_list = cursor.fetchall()
    # 关闭游标对象
    cursor.close()
    # 关闭连接对象
    conn.close()

    f = open('hostlist.html','r',encoding='utf-8')
    data = f.read()
    f.close()

    # 基于第三方工具实现的模板渲染
    from jinja2 import Template
    template = Template(data)
    # 调用render()方法完成字符串的替换,这里要注意,前后端特殊语法要相同
    data = template.render(user_list=user_list,user='sdfsdfsdf')
    return data.encode('utf-8')

# 路由与函数的对应关系
routers = [
    ('/xxx', f1),
    ('/ooo', f2),
    ('/userlist.htm', f3),
    ('/host.html', f4),
]


def run():
    # 获取socket对象
    sock = socket.socket()
    # 绑定ip地址和端口
    sock.bind(('127.0.0.1',8080))
    # 开始监听(设置最大监听数5个)
    sock.listen(5)

    while True:
        conn,addr = sock.accept() # 夯住,等待用户连接
        # 获取用户发送的数据
        data = conn.recv(8096)
        # 直接转换为字符串
        data = str(data,encoding='utf-8')
        # 根据http协议划分请求头和请求体


        headers,bodys = data.split('

')
        # 根据已有的http协议数据结构切分元素
        temp_list = headers.split('
')
        # 分别获取请求方法、请求url地址、请求协议类型
        method,url,protocal = temp_list[0].split(' ')
        conn.send(b"HTTP/1.1 200 OK

")

        func_name = None    # 设置标志位
        for item in routers:
            # 遍历url与函数对应关系表,并判断当前请求url是否相等
            if item[0] == url:
                # 能对应就获取函数名并停止循环
                func_name = item[1]
                break

        if func_name:
            # 有这个函数就加括号调用并传入参数
            response = func_name(data)
        else:
            response = b"404"
        # 返回函数处理后的结果
        conn.send(response)
        conn.close()

if __name__ == '__main__':
    run()
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <table border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <th>1</th>
                <!-- 自定义字符串替换的特殊语法 -->
                <th>@@sw@@</th>
                <th>root@qq.com</th>
            </tr>
        </tbody>
    </table>
</body>
</html>
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <table border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
            {% for row in user_list %}
            <!--使用第三方模板,就要遵循他的语法规则-->
                <tr>
                    <td>{{row.id}}</td>
                    <td>{{row.username}}</td>
                    <td>{{row.password}}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    {{user}}
</body>
</html>
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>用户登录</h1>
    <form>
        <p><input type="text" placeholder="用户名" /></p>
        <p><input type="password" placeholder="密码" /></p>
    </form>
</body>
</html>
View Code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <table border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
        <!--自定义模板特殊语法-->
            @@sdfsdffd@@
        </tbody>
    </table>
</body>
</html>
View Code

4.总结

有以上我们模拟网站(socket服务端)和浏览器(socket客户端)的知识知道了:
1.http是建立在tcp之上的,无状态的,短链接,一次请求一次响应。  而TCP是不断开的长连接。
2.http协议是固定的键值对组合,每个键值对之间由
分割,请求头和请求体之间则是由两个

分割。而响应头和响应体也是这样的组合。
3.自己写的网站必须具备以下要素:
    a.socket服务端
    b.根据url的不同,返回不同的内容(url与函数的对应关系)
    c.返回字符串给用户(模板引擎渲染:HTML充当模板和特殊字符,自己定义任意数据)

而web框架的种类也是根据以上三点相结合:
    框架自带a,b,c              Tornado
    [第三方a],b,c              wsgiref服务网关接口、Django 
    [第三方a],b,[第三方c]   wsgiref服务网关接口、Flask、jinja2模板
按照另一种维度划分:
     重量级:Django
     轻量级:Tornado、Flask
原文地址:https://www.cnblogs.com/Guishuzhe/p/9761105.html