本身動手寫出靜態網站與動態網站

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協議劃分請求頭和請求體\r\n\r\n
        headers,bodys = data.split('\r\n\r\n')
        # 根據已有的http協議數據結構切分元素
        temp_list = headers.split('\r\n')
        # 分別獲取請求方法、請求url地址、請求協議類型
        method,url,protocal = temp_list[0].split(' ')
        conn.send(b"HTTP/1.1 200 OK\r\n\r\n")

        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協議劃分請求頭和請求體\r\n\r\n
        headers,bodys = data.split('\r\n\r\n')
        # 根據已有的http協議數據結構切分元素
        temp_list = headers.split('\r\n')
        # 分別獲取請求方法、請求url地址、請求協議類型
        method,url,protocal = temp_list[0].split(' ')
        conn.send(b"HTTP/1.1 200 OK\r\n\r\n")

        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協議是固定的鍵值對組合,每一個鍵值對之間由\r\n分割,請求頭和請求體之間則是由兩個\r\n\r\n分割。而響應頭和響應體也是這樣的組合。
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
相關文章
相關標籤/搜索