加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Python 利用三个简易模块熟悉前后端交互流程

发布时间:2020-12-15 17:12:01 所属栏目:大数据 来源:网络整理
导读:准备工作 在学习 Django 之前,先动手撸一个简单的 WEB 框架来熟悉一下前后端交互的整体流程 本次用到的模块: 1. wsgiref ,这是一个 Python 自带的模块,用于构建路由与视图 2. pymysql ,第三方模块,用于数据库与视图层进行数据交互 3. jinja2 ,第三方

准备工作

   在学习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 rnrn","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",]

# run.py

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

def run(request,response):
    
    """
    request:① 请求相关的所有数据
    response:② 响应相关的数据
    return:③  返回给浏览器的数据
    """

    response("200 OK",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 # 启动相关代码

<!DOCTYPE html>
<html lang="en">

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

        .carousel-inner>.item>img 
            position absolute
            top 0
            left
            min-width 100%}
    body>

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

             Collect the nav links,forms,and other content for toggling ="collapse navbar-collapse" id="bs-example-navbar-collapse-1"form ="navbar-form navbar-left"="form-group">
                        input ="text"="form-control" placeholder="Search"="submit"="btn btn-default">Submitformul ="nav navbar-nav navbar-right"li><="HTTP://127.0.0.1:8080/login">LOGIN>REGISTERul> /.navbar-collapse -->
         /.container-fluid -->
    nav>


    >

        ="row"="col-xs-12 col-sm-12 col-md-12 col-lg-12 input-lg-5g bg-primar "="page-header"h1>Example page header small>Subtext for header="col-xs-3 col-sm-3 col-md-3 col-lg-3"="list-group"="#"="list-group-item active"
                        Cras justo odio
                    ="list-group-item">Dapibus ac facilisis in>Morbi leo risus>Porta ac consectetur ac>Vestibulum at eros="col-xs-9 col-sm-9 col-md-9 col-lg-9"id="carousel-example-generic"="carousel slide" data-ride="carousel" Indicators -->
                    ol ="carousel-indicators"li data-target="#carousel-example-generic" data-slide-to="0"="active"="1"ol>

                     Wrapper for slides ="carousel-inner"="item active">
                            img ="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="..."="item"="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" Controls ="left carousel-control" role data-slide="prev"="glyphicon glyphicon-chevron-left" aria-hidden="true">Previous="right carousel-control"="next"="glyphicon glyphicon-chevron-right">Nexthtml>
index.html


        body 
            display flex
            justify-content center
            align-self 100vh rebeccapurple;

        

        form.form1 
            flex-flow column
            border 1px solid #ddd
            padding 10px
            width 30% white
            border-radius 15px>



    ="form1" actionlabel for="exampleInputEmail1">usernamelabel="email"="exampleInputEmail1"="please enter user name"="exampleInputPassword1">Password="password"="exampleInputPassword1"
                placeholder="please enter user password"="btn btn-default" disabled>


>
login.html

   除此之外,还要将视图中index函数与login函数的返回结果改一下

# 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",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文件进行操作。

import pymysql


 DbServer(object):
    def __init__(self):
        self.conn = pymysql.connect(
            host="localhost",database=db1utf8mb4root# 记录结果,字典显示
            autocommit=True,1)"> 自动提交
        )

        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,1)">None):
        pass

    def drop(self,1)">def deletle(self,1)">__del__(self):
         关闭程序前关闭链接与游标
        self.cursor.close()
        self.conn.close()

if __name__ != '__main__':  不能当作独立文件进行运行
    dbserver = DbServer()
db.py

   记得在数据库中先插入数据

create table user(
    id INT PRIMARY KEY AUTO_INCREMENT,name CHAR(12) NOT NULL,password CHAR(12 添加索引
);

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

   别忘了在view.py中进行导入,与此同时,还要写一个验证功能。

from db.db  dbserver
 jinja2

def index(request):
    with open(file=template/index.htmlrutf-8) as f:
        res = f.read()
    return res


 login(request):
    with open(file=template/login.html login_verif(request):
     GET 请求  QUERY_STRING
    request_msg = request.get(QUERY_STRING&)
    user_dict = {}

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

     index(request):
        with open(file=) as f:
            res = f.read()
         res

     login(request):
        with open(file= res

 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:
        Login failed,no such user"

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

   还要在urls.py文件中增加验证的路由解析。

from view.view import *

urls = [
    (/index/login/login_verifurls.py

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

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

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

jinja2

   在验证完成后,我们应该根据用户名与密码是否正确来返回不同的内容。

   这个时候可以使用jinja2的模板语言了。

   首先在Template文件夹下新建一个verification.html做验证

   然后修改一下view中的login_verif代码

>
    
    ="container">
        
        ="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 "
                    {% if login_msg.status %}
                        >欢迎回家{{login_msg.username}}
                    {% else %}
                        >无此用户!请检查用户名或密码是否输入正确
                    {% endif %}
                  >
        
    >
    

>
verification.html

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

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,val=None):
        res = self.cursor.execute(sql,val)
        return res,self.cursor.fetchone()  # 返回查找行数,查找结果

    def insert(self,val=None):
        pass

    def drop(self,val=None):
        pass

    def deletle(self,val=None):
        pass

    def __del__(self):
        # 关闭程序前关闭链接与游标
        self.cursor.close()
        self.conn.close()

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

   template - index.html

>
View Code

   template - login.html

="http://127.0.0.1:8080/login_verif"="username"="username" name="password">
View Code

   template - verifcation.html

>
    
>
View Code

   urls - urls.py

from view.view import *

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

   view - view.py

from db.db import dbserver
import jinja2

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


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


def login_verif(request):
    # GET 请求  QUERY_STRING
    request_msg = request.get("QUERY_STRING",value = msg.split("=")
        user_dict[key] = value
    from db.db import dbserver

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

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

def login_verif(request):
    # GET 请求  QUERY_STRING
    request_msg = request.get("QUERY_STRING",encoding="utf-8") as f:
        data = f.read()

    tmp = jinja2.Template(data)

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

    res = tmp.render(login_msg=msg) # 返回登录信息 
    return res

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

   run.py

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

def run(request,response):
   
    """
    request:① 请求相关的所有数据
    response:② 响应相关的数据
    return:③  返回给浏览器的数据
    """

    response("200 OK",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,权限管理等等,这些都会在之后慢慢做介绍。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读