Python 利用三個簡易模組熟悉前後端互動流程

雲崖先生發表於2020-09-07

準備工作

   在學習Django之前,先動手擼一個簡單的WEB框架來熟悉一下前後端互動的整體流程

   本次用到的模組:

   1.wsgiref,這是一個Python自帶的模組,用於構建路由與檢視

   2.pymysql,第三方模組,用於資料庫與檢視層進行資料互動

   3.jinja2,第三方模組,用於對前端頁面進行模板渲染

   請使用pip install modulename進行安裝

   如果安裝jinja2失敗,請使用easy_install Jinja2命令進行安裝

資料互動

   其實前面已經有大量的地方討論瀏覽器與後端伺服器如何進行互動,也用socket進行實現過簡單的互動,但是我們需要在前者基礎上做一個優化,即使用者在位址列輸入什麼路徑,就返回請求的路徑名字。

   當這個需求完成後,我們就可以根據不同的請求路徑,返回出不同的HTML文件資訊,但是使用原生的socket這個過程會十分的繁瑣,所以用一次就放棄吧。

from socket import *

def run():
    server = socket(AF_INET, SOCK_STREAM)  # 傳輸層基於TCP協議
    server.bind(("127.0.0.1", 8080))
    server.listen(5)

    while 1:

        conn, addr = server.accept()
        try:  # 防止Windows平臺下Client端異常關閉導致雙向連結崩塌Server端異常的情況發生
            data = conn.recv(1024)
            if not data:  # bug修復:針對類UNIX環境
                continue
                
            request_path = data.decode("utf-8").split(" ")[1] # 拿到請求的路徑
            conn.sendall(bytes("HTTP/1.1 201 OK \r\n\r\n", "utf8"))  # 返回響應頭
            conn.sendall(bytes("<h1>{0}</h1>".format(request_path), "utf8"))  # 返回響應體
            
        except Exception:
            continue

    conn.close()

if __name__ == '__main__':
    run()

   socket

wsgiref

   以下是利用wsgiref實現上面的功能,簡單了許多,並且程式碼變得更加明瞭。

   此外新增加了訪問路徑不存在時給出404錯誤提示。

from wsgiref.simple_server import make_server

def index(request):
    return "You visited index"

def login(request):
    return "You visited login"

def error(request):
    return "404 Resource request error"

urls = [
    ("/index", index),
    ("/login", login),
]

def run(request, response):

    """
    request:① 請求相關的所有資料
    response:② 響應相關的資料
    return:③  返回給瀏覽器的資料
    """

    response("200 OK",[]) # 響應首行,響應頭
    func = None
    request_path = request.get("PATH_INFO") # 拿到路徑

    for url in urls:
        if request_path == url[0]:
            func = url[1]
            break # 匹配到後結束for迴圈

    if func:
        res = func(request)
    else:
        res = error(request)

    return [res.encode("utf-8")]

if __name__ == '__main__':
    server = make_server("localhost", 8080, run)
    # ③ 實時監聽127.0.0.1:8080地址,只要有連結請求,都交給run函式處理
    server.serve_forever() # ④ 開啟服務

   wsgiref

程式碼解耦

   我們對上述程式碼進行解耦,將不同功能的程式碼放在不同的資料夾下。

  

-- webproject
	-- view # 檢視相關程式碼
		-- view.py
	-- urls # 路由相關程式碼
		-- urls.py
	-- run.py # 啟動相關程式碼
# view.py

def index(request):
    return "You visited index"

def login(request):
    return "You visited login"

def error(request):
    return "404 Resource request error"
# urls.py

from view.view import *

urls = [
    ("/index", index),
    ("/login", login),
]

# run.py

from wsgiref.simple_server import make_server
from urls.urls import *

def run(request, response):
    
    """
    request:① 請求相關的所有資料
    response:② 響應相關的資料
    return:③  返回給瀏覽器的資料
    """

    response("200 OK",[]) # 響應首行,響應頭
    func = None
    request_path = request.get("PATH_INFO") # 拿到路徑

    for url in urls:
        if request_path == url[0]:
            func = url[1]
            break # 匹配到後結束for迴圈

    if func:
        res = func(request)
    else:
        res = error(request)

    return [res.encode("utf-8")]

if __name__ == '__main__':
    server = make_server("localhost", 8080, run)
    # ③ 實時監聽127.0.0.1:8080地址,只要有連結請求,都交給run函式處理
    server.serve_forever() # ④ 開啟服務

返回頁面

   繼續上面的流程,已經將程式碼進行解耦了,此時我們新建一個template資料夾用於專門存放返回的網頁。

   並在該資料夾下新建index.html以及login.html

-- webproject
	-- view # 檢視相關程式碼
		-- view.py
	-- urls # 路由相關程式碼
		-- urls.py
	-- template # 前端頁面
		-- index.html
		-- login.html
	-- run.py # 啟動相關程式碼
Python 利用三個簡易模組熟悉前後端互動流程
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src='https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js'></script>
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css'
        integrity='sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u' crossorigin='anonymous'>
    <script src='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js'
        integrity='sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa'
        crossorigin='anonymous'></script>
    <title>Document</title>
    <style>
        
        .carousel .item {
            height: 400px;
            background-color: #777;
        }

        .carousel-inner>.item>img {
            position: absolute;
            top: 0;
            left: 0;
            min-width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>

    <nav class="navbar navbar-inverse">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">INDEX</a>
            </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <form class="navbar-form navbar-left">
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Search">
                    </div>
                    <button type="submit" class="btn btn-default">Submit</button>
                </form>
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="HTTP://127.0.0.1:8080/login">LOGIN</a></li>
                    <li><a href="#">REGISTER</a></li>
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>


    <div class="container-fluid">

        <div class="row">
            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 input-lg-5g bg-primar ">
                <div class="page-header">
                    <h1>Example page header <small>Subtext for header</small></h1>
                </div>
            </div>

            <div class="col-xs-3 col-sm-3 col-md-3 col-lg-3">
                <div class="list-group">
                    <a href="#" class="list-group-item active">
                        Cras justo odio
                    </a>
                    <a href="#" class="list-group-item">Dapibus ac facilisis in</a>
                    <a href="#" class="list-group-item">Morbi leo risus</a>
                    <a href="#" class="list-group-item">Porta ac consectetur ac</a>
                    <a href="#" class="list-group-item">Vestibulum at eros</a>
                </div>
            </div>

            <div class="col-xs-9 col-sm-9 col-md-9 col-lg-9">
                <div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
                    <!-- Indicators -->
                    <ol class="carousel-indicators">
                        <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
                        <li data-target="#carousel-example-generic" data-slide-to="1"></li>
                    </ol>

                    <!-- Wrapper for slides -->
                    <div class="carousel-inner">
                        <div class="item active">
                            <img src="https://tse4-mm.cn.bing.net/th/id/OIP._PbxAuEi3ce9S1DtQ3KilwHaEK?w=306&h=180&c=7&o=5&dpr=1.25&pid=1.7"
                                alt="...">
                        </div>
                        <div class="item">
                            <img src="https://tse2-mm.cn.bing.net/th/id/OIP.Det5e8us-qsNAGEhnL6u0AHaF7?w=238&h=190&c=7&o=5&dpr=1.25&pid=1.7"
                                alt="...">
                        </div>
                    </div>

                    <!-- Controls -->
                    <a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
                        <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
                        <span class="sr-only">Previous</span>
                    </a>
                    <a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
                        <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                        <span class="sr-only">Next</span>
                    </a>
                </div>
            </div>

        </div>

    </div>

</body>

</html>
index.html
Python 利用三個簡易模組熟悉前後端互動流程
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src='https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js'></script>
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css'
        integrity='sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u' crossorigin='anonymous'>
    <script src='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js'
        integrity='sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa'
        crossorigin='anonymous'></script>

    <style>
        body {
            display: flex;
            justify-content: center;
            align-self: center;
            height: 100vh;
            background-color: rebeccapurple;

        }

        form.form1 {
            display: flex;
            flex-flow: column;
            justify-content: center;
            align-self: center;
            border: 1px solid #ddd;
            padding: 10px;
            width: 30%;
            background-color: white;
            border-radius: 15px;
        }
    </style>

</head>

<body>



    <form class="form1" action="#">
        <div class="form-group">
            <label for="exampleInputEmail1">username</label>
            <input type="email" class="form-control" id="exampleInputEmail1" placeholder="please enter user name">
        </div>
        <div class="form-group">
            <label for="exampleInputPassword1">Password</label>
            <input type="password" class="form-control" id="exampleInputPassword1"
                placeholder="please enter user password">
        </div>

        <button type="submit" class="btn btn-default" disabled>Submit</button>
    </form>


</body>

</html>
login.html

   除此之外,還要將檢視中index函式與login函式的返回結果改一下

Python 利用三個簡易模組熟悉前後端互動流程
# view.py

def index(request):
    with open(file="template/index.html",mode="r",encoding="utf-8") as f:
        res = f.read()
    return res

def login(request):
    with open(file="template/login.html",mode="r",encoding="utf-8") as f:
        res = f.read()
    return res

def error(request):
    return "404 Resource request error"
view.py

   那麼目前,我們的框架已經初具雛形了,能夠根據請求路徑的不同返回不同的HTML文件。

pymsql

   繼續接著做邏輯,點選login後輸入使用者名稱和密碼提交完應該對資料庫進行驗證,判斷該使用者是否存在。

   那麼現在我們就需要用到pymysql模組了,還是新建一個資料夾叫db,然後建立db檔案進行操作。

Python 利用三個簡易模組熟悉前後端互動流程
import pymysql


class DbServer(object):
    def __init__(self):
        self.conn = pymysql.connect(
            host="localhost",
            database="db1",
            charset="utf8mb4",
            user="root",
            cursorclass=pymysql.cursors.DictCursor,  # 記錄結果,字典顯示
            autocommit=True,  # 自動提交
        )

        self.cursor = self.conn.cursor()

    def select(self, sql, val=None):
        res = self.cursor.execute(sql, val)
        return res, self.cursor.fetchone()  # 返回查詢行數,查詢結果

    def insert(self, sql, val=None):
        pass

    def drop(self, sql, val=None):
        pass

    def deletle(self, sql, val=None):
        pass

    def __del__(self):
        # 關閉程式前關閉連結與遊標
        self.cursor.close()
        self.conn.close()

if __name__ != '__main__': # 不能當作獨立檔案進行執行
    dbserver = DbServer()
db.py

   記得在資料庫中先插入資料

Python 利用三個簡易模組熟悉前後端互動流程
create table user(
    id INT PRIMARY KEY AUTO_INCREMENT,
    name CHAR(12) NOT NULL,
    password CHAR(12) NOT NULL,
    INDEX(name) -- 新增索引
);

INSERT INTO  user(name,password) VALUES
    ("Yunya","123456");
MySQL命令

   別忘了在view.py中進行匯入,與此同時,還要寫一個驗證功能。

Python 利用三個簡易模組熟悉前後端互動流程
from db.db import dbserver
import jinja2

def index(request):
    with open(file="template/index.html", mode="r", encoding="utf-8") as f:
        res = f.read()
    return res


def login(request):
    with open(file="template/login.html", mode="r", encoding="utf-8") as f:
        res = f.read()
    return res


def login_verif(request):
    # GET 請求  QUERY_STRING
    request_msg = request.get("QUERY_STRING", None).split("&")
    user_dict = {}

    for msg in request_msg:
        key, value = msg.split("=")
        user_dict[key] = value
    from db.db import dbserver

    def index(request):
        with open(file="template/index.html", mode="r", encoding="utf-8") as f:
            res = f.read()
        return res

    def login(request):
        with open(file="template/login.html", mode="r", encoding="utf-8") as f:
            res = f.read()
        return res

def login_verif(request):
    # GET 請求  QUERY_STRING
    request_msg = request.get("QUERY_STRING", None).split("&")
    user_dict = {}

    for msg in request_msg:
        key, value = msg.split("=")
        user_dict[key] = value

    sql = "select * from user where name=%s and password = %s"
    val = (user_dict.get("username"), user_dict.get("password"))
    result = dbserver.select(sql, val)
    if result[0]:
        return "Welcome" + result[1].get("name")
    else:
        return "Login failed, no such user"

def error(request):
    return "404 Resource request error"
view.py

   還要在urls.py檔案中增加驗證的路由解析。

Python 利用三個簡易模組熟悉前後端互動流程
from view.view import *

urls = [
    ("/index", index),
    ("/login", login),
    ("/login_verif", login_verif),
]
urls.py

   最後一步修改前端login.html中的form提交路徑

Python 利用三個簡易模組熟悉前後端互動流程
  <form class="form1" action="http://127.0.0.1:8080/login_verif">
        <div class="form-group">
            <label for="username">username</label>
            <input type="text" id="username" name="username" class="form-control" placeholder="please enter user name">
        </div>
        <div class="form-group">
            <label for="password">Password</label>
            <input type="password" id="password" name="password" class="form-control"
                placeholder="please enter user password">
        </div>

        <button type="submit" class="btn btn-default">Submit</button>
    </form>
login.html

jinja2

   在驗證完成後,我們應該根據使用者名稱與密碼是否正確來返回不同的內容。

   這個時候可以使用jinja2的模板語言了。

   首先在Template資料夾下新建一個verification.html做驗證

   然後修改一下view中的login_verif程式碼

Python 利用三個簡易模組熟悉前後端互動流程
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
    <div class="container">
        
        <div class="row">
            <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 col-xs-offset-3 col-sm-offset-3 col-md-offset-3  col-lg-offset-3 ">
                <div class="page-header">
                    {% if login_msg.status %}
                        <h1>歡迎回家{{login_msg.username}}</h1>
                    {% else %}
                        <h1>無此使用者!請檢查使用者名稱或密碼是否輸入正確</h1>
                    {% endif %}
                  </div>
            </div>
        </div>
        
    </div>
    

</body>
</html>
verification.html
Python 利用三個簡易模組熟悉前後端互動流程
def login_verif(request):
    # GET 請求  QUERY_STRING
    request_msg = request.get("QUERY_STRING", None).split("&")
    user_dict = {}

    for msg in request_msg:
        key, value = msg.split("=")
        user_dict[key] = value

    sql = "select * from user where name=%s and password = %s"
    val = (user_dict.get("username"), user_dict.get("password"))
    result = dbserver.select(sql, val)

    with open("./template/verification.html","r",encoding="utf-8") as f:
        data = f.read()

    tmp = jinja2.Template(data) # 做成模板

    if result[0]:
        msg = {"username":result[1].get("name"),"status":1}
       
    else:
        msg = {"username":None,"status":0}

    res = tmp.render(login_msg=msg) # 模板中新增變數
    return res
view.py def login_verif

成果演示

程式碼總和

   db - db.py

Python 利用三個簡易模組熟悉前後端互動流程
import pymysql


class DbServer(object):
    def __init__(self):
        self.conn = pymysql.connect(
            host="localhost",
            database="db1",
            charset="utf8mb4",
            user="root",
            cursorclass=pymysql.cursors.DictCursor,  # 記錄結果,字典顯示
            autocommit=True,  # 自動提交
        )

        self.cursor = self.conn.cursor()

    def select(self, sql, val=None):
        res = self.cursor.execute(sql, val)
        return res, self.cursor.fetchone()  # 返回查詢行數,查詢結果

    def insert(self, sql, val=None):
        pass

    def drop(self, sql, val=None):
        pass

    def deletle(self, sql, val=None):
        pass

    def __del__(self):
        # 關閉程式前關閉連結與遊標
        self.cursor.close()
        self.conn.close()

if __name__ != '__main__':
    dbserver = DbServer()
View Code

   template - index.html

Python 利用三個簡易模組熟悉前後端互動流程
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src='https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js'></script>
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css'
        integrity='sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u' crossorigin='anonymous'>
    <script src='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js'
        integrity='sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa'
        crossorigin='anonymous'></script>
    <title>Document</title>
    <style>
        
        .carousel .item {
            height: 400px;
            background-color: #777;
        }

        .carousel-inner>.item>img {
            position: absolute;
            top: 0;
            left: 0;
            min-width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>

    <nav class="navbar navbar-inverse">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">INDEX</a>
            </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <form class="navbar-form navbar-left">
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Search">
                    </div>
                    <button type="submit" class="btn btn-default">Submit</button>
                </form>
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="HTTP://127.0.0.1:8080/login">LOGIN</a></li>
                    <li><a href="#">REGISTER</a></li>
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>


    <div class="container-fluid">

        <div class="row">
            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 input-lg-5g bg-primar ">
                <div class="page-header">
                    <h1>Example page header <small>Subtext for header</small></h1>
                </div>
            </div>

            <div class="col-xs-3 col-sm-3 col-md-3 col-lg-3">
                <div class="list-group">
                    <a href="#" class="list-group-item active">
                        Cras justo odio
                    </a>
                    <a href="#" class="list-group-item">Dapibus ac facilisis in</a>
                    <a href="#" class="list-group-item">Morbi leo risus</a>
                    <a href="#" class="list-group-item">Porta ac consectetur ac</a>
                    <a href="#" class="list-group-item">Vestibulum at eros</a>
                </div>
            </div>

            <div class="col-xs-9 col-sm-9 col-md-9 col-lg-9">
                <div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
                    <!-- Indicators -->
                    <ol class="carousel-indicators">
                        <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
                        <li data-target="#carousel-example-generic" data-slide-to="1"></li>
                    </ol>

                    <!-- Wrapper for slides -->
                    <div class="carousel-inner">
                        <div class="item active">
                            <img src="https://tse4-mm.cn.bing.net/th/id/OIP._PbxAuEi3ce9S1DtQ3KilwHaEK?w=306&h=180&c=7&o=5&dpr=1.25&pid=1.7"
                                alt="...">
                        </div>
                        <div class="item">
                            <img src="https://tse2-mm.cn.bing.net/th/id/OIP.Det5e8us-qsNAGEhnL6u0AHaF7?w=238&h=190&c=7&o=5&dpr=1.25&pid=1.7"
                                alt="...">
                        </div>
                    </div>

                    <!-- Controls -->
                    <a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
                        <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
                        <span class="sr-only">Previous</span>
                    </a>
                    <a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
                        <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
                        <span class="sr-only">Next</span>
                    </a>
                </div>
            </div>

        </div>

    </div>

</body>

</html>
View Code

   template - login.html

Python 利用三個簡易模組熟悉前後端互動流程
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src='https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js'></script>
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css'
        integrity='sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u' crossorigin='anonymous'>
    <script src='https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js'
        integrity='sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa'
        crossorigin='anonymous'></script>

    <style>
        body {
            display: flex;
            justify-content: center;
            align-self: center;
            height: 100vh;
            background-color: rebeccapurple;

        }

        form.form1 {
            display: flex;
            flex-flow: column;
            justify-content: center;
            align-self: center;
            border: 1px solid #ddd;
            padding: 10px;
            width: 30%;
            background-color: white;
            border-radius: 15px;
        }
    </style>

</head>

<body>



    <form class="form1" action="http://127.0.0.1:8080/login_verif">
        <div class="form-group">
            <label for="username">username</label>
            <input type="text" id="username" name="username" class="form-control" placeholder="please enter user name">
        </div>
        <div class="form-group">
            <label for="password">Password</label>
            <input type="password" id="password" name="password" class="form-control"
                placeholder="please enter user password">
        </div>

        <button type="submit" class="btn btn-default">Submit</button>
    </form>


</body>

</html>
View Code

   template - verifcation.html

Python 利用三個簡易模組熟悉前後端互動流程
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
    <div class="container">
        
        <div class="row">
            <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 col-xs-offset-3 col-sm-offset-3 col-md-offset-3  col-lg-offset-3 ">
                <div class="page-header">
                    {% if login_msg.status %}
                        <h1>歡迎回家{{login_msg.username}}</h1>
                    {% else %}
                        <h1>無此使用者!請檢查使用者名稱或密碼是否輸入正確</h1>
                    {% endif %}
                  </div>
            </div>
        </div>
        
    </div>
    
</body>
</html>
View Code

   urls - urls.py

Python 利用三個簡易模組熟悉前後端互動流程
from view.view import *

urls = [
    ("/index", index),
    ("/login", login),
    ("/login_verif", login_verif),
]
View Code

   view - view.py

Python 利用三個簡易模組熟悉前後端互動流程
from db.db import dbserver
import jinja2

def index(request):
    with open(file="template/index.html", mode="r", encoding="utf-8") as f:
        res = f.read()
    return res


def login(request):
    with open(file="template/login.html", mode="r", encoding="utf-8") as f:
        res = f.read()
    return res


def login_verif(request):
    # GET 請求  QUERY_STRING
    request_msg = request.get("QUERY_STRING", None).split("&")
    user_dict = {}

    for msg in request_msg:
        key, value = msg.split("=")
        user_dict[key] = value
    from db.db import dbserver

    def index(request):
        with open(file="template/index.html", mode="r", encoding="utf-8") as f:
            res = f.read()
        return res

    def login(request):
        with open(file="template/login.html", mode="r", encoding="utf-8") as f:
            res = f.read()
        return res

def login_verif(request):
    # GET 請求  QUERY_STRING
    request_msg = request.get("QUERY_STRING", None).split("&")
    user_dict = {}

    for msg in request_msg:
        key, value = msg.split("=")
        user_dict[key] = value

    sql = "select * from user where name=%s and password = %s"
    val = (user_dict.get("username"), user_dict.get("password"))
    result = dbserver.select(sql, val)

    with open("./template/verification.html","r",encoding="utf-8") as f:
        data = f.read()

    tmp = jinja2.Template(data)

    if result[0]:
        msg = {"username":result[1].get("name"),"status":1}
       
    else:
        msg = {"username":None,"status":0}

    res = tmp.render(login_msg=msg) # 返回登入資訊 
    return res

def error(request):
    return "404 Resource request error"
View Code

   run.py

Python 利用三個簡易模組熟悉前後端互動流程
from wsgiref.simple_server import make_server
from urls.urls import *

def run(request, response):
   
    """
    request:① 請求相關的所有資料
    response:② 響應相關的資料
    return:③  返回給瀏覽器的資料
    """

    response("200 OK",[]) # 響應首行,響應頭
    func = None
    request_path = request.get("PATH_INFO") # 拿到路徑

    for url in urls:
        if request_path == url[0]:
            func = url[1]
            break # 匹配到後結束for迴圈

    if func:
        res = func(request)
    else:
        res = error(request)

    return [res.encode("utf-8")]

if __name__ == '__main__':
    server = make_server("localhost", 8080, run)
    # ③ 實時監聽127.0.0.1:8080地址,只要有連結請求,都交給run函式處理
    server.serve_forever() # ④ 開啟服務
View Code

最後結論

   其實通過這三個基礎模組,相信你已經瞭解了其基本的流程,但是用這三個模組來做成一個建議的Web框架還是存在大量的不足。

   1.HTML檔案程式碼冗餘過度

   2.提交全部為GET方式,這使得密碼等傳輸極度不安全

   3.原生SQL語句操縱資料庫,開發效率偏低

   4.路由的URL解析太過死板,不能靈活解析

   這些不足點在Django框架中都會有非常好的解決方案,因此Django框架是學習PythonWeb的首選。

   總之前後端互動的大體流程就是這樣,前端給請求路徑,後端根據路徑查詢資料庫中資料並進行處理後返回HTML文件再由模板語言進行解析(前後端不分離),最終呈現出一個完整的動態頁面。

   當然還有很多知識點沒有涉及到,如cookieajax,許可權管理等等,這些都會在之後慢慢做介紹。

相關文章