一:概述:
web框架专门处理动态资源的请求。web服务器接收浏览器发起的请求,如果是动态资源请求找web框架来处理。web框架负责处理浏览器的动态资源请求,把处理的结果返回给web服务器。web服务器再把响应结果返回给浏览器。
二:实现过程:假定以.html结尾的是动态资源。
1:搭建基本框架:
web服务器如何写?
思路:拿到请求资源路径后,判断是不是以.html结尾,如果是,将请求封装成字典,然后把字典交给框架进行处理,框架返回状态码,响应头,和响应体。然后web服务器,把返回的信息拼接成响应信息,发送给浏览器。
web框架如何写?
首先拿到请求资源路径,判断资源路径是/index.html还是其他的,如果是/index.html则交给index函数处理,如果是其他的,则交给not_fond函数处理。而两个函数分别创建自己的状态码,响应头,和响应体,然后返回给web服务器。其中index函数用时间模拟找到的数据。
# 判断是否是动态资源请求
if request_path.endswith(".html"):
"""这里是动态资源请求,把请求信息交给框架处理"""
# 字典存储用户的请求信息
env = {
"request_path": request_path
}
# 获取处理结果
status, headers, response_body = framework.handle_request(env)
# 使用框架处理的数据拼接响应报文
# 响应行
response_line = "HTTP/1.1 %s\r\n" % status
# 响应头
response_header = ""
# 遍历头部信息
for header in headers:
# 拼接多个响应头
response_header += "%s: %s\r\n" % header
response_data = (response_line +
response_header +
"\r\n" +
response_body).encode("utf-8")
# 发送数据
new_socket.send(response_data)
# 关闭socket
new_socket.close()
else:
"""这里是静态资源请求"""
"""miniweb框架,负责处理动态资源请求"""
import time
# 获取首页数据
def index():
# 响应状态
status = "200 OK";
# 响应头
response_header = [("Server", "PWS2.0")]
# 处理后的数据
data = time.ctime()
return status, response_header, data
# 没有找到动态资源
def not_found():
# 响应状态
status = "404 Not Found";
# 响应头
response_header = [("Server", "PWS2.0")]
# 处理后的数据
data = "not found"
return status, response_header, data
# 处理动态资源请求
def handle_request(env):
# 获取动态请求资源路径
request_path = env["request_path"]
print("接收到的动态资源请求:", request_path)
if request_path == "/index.html":
# 获取首页数据
result = index()
return result
else:
# 没有找到动态资源
result = not_found()
return result
开启web服务器:
python3 web.py 8888
此时当我们访问index页面的时候:只有Fri Aug 21 17:46:58 2020。
2:模板代替功能开发:
思路:框架打开index文件,读取里面的数据,将模板中的要代替的数据先用当前时间来替换,然后返回给web服务器。
# 获取首页数据
def index():
# 响应状态
status = "200 OK";
# 响应头
response_header = [("Server", "PWS2.0")]
# 1. 打开模板文件,读取数据
with open("template/index.html", "r") as file:
file_data = file.read()
# 处理后的数据, 从数据库查询
data = time.ctime()
# 2. 替换模板文件中的模板遍历
result = file_data.replace("{%content%}", data)
return status, response_header, result
3:路由列表的开发:
问题:现在我们想再增加请求:那么就需要在web框架增加一个函数单独处理。例如增加一个center页面的处理过程。如果页面再次增多,比如100个页面就需要100if else判断,能不能简化代码呢?
if request_path == "/index.html":
# 获取首页数据
result = index()
return result
elif request_path == "/center.html":
# 获取个人中心数据
result = center()
return result
else:
# 没有找到动态资源
result = not_found()
return result
# 获取个人中心数据
def center():
# 响应状态
status = "200 OK";
# 响应头
response_header = [("Server", "PWS2.0")]
# 打开模板文件,读取数据
with open("template/center.html", "r") as file:
file_data = file.read()
# 处理后的数据, 从数据库查询
data = time.ctime()
# 替换模板文件中的模板遍历
result = file_data.replace("{%content%}", data)
return status, response_header, result
路由列表思路:定义一个路由列表,里面存储页面路径和函数的对应关系,每次有资源请求遍历路由列表,如果能找到就调用函数。如果找不到就返回报错信息。
route_list = [
("/index.html", index),
("/center.html", center)
]
def handle_request(env):
# 获取动态请求资源路径
request_path = env["request_path"]
print("接收到的动态资源请求:", request_path)
# 遍历路由列表,选择执行的函数
for path, func in route_list:
if request_path == path:
result = func()
return result
else:
# 没有找到动态资源
result = not_found()
return result
4:装饰器的方式添加路由:
问题:每次添加路由都需要手动添加来完成,接下来我们想要完成路由的自动添加,可以通过装饰器来实现。
思路:首先定义一个空列表,然后定义一个带参数的装饰器,装饰器外面的函数可以接收,路径地址,而装饰器的外层函数可以接受处理的函数,所以正好匹配成一对数据。这样在装饰器外层函数内部,内层函数外部的位置,可以追加列表,这样就构造成了路由列表。
# 定义路由列表
route_list = []
# 定义带有参数的装饰器
def route(path):
# 装饰器
def decorator(func):
# 当执行装饰器装饰指定函数的时候,把路径和函数添加到路由列表
route_list.append((path, func))
def inner():
# 执行指定函数
return func()
return inner
# 返回装饰器
return decorator
给方法增加语法糖过程省略。
问题:1:遍历路由列表前,路由列表是否构造完成??
答:路由列表的构造是在web.py导入framework.py的时候就已经加载好了,所以遍历路由列表前,路由列表已经构造完成。
问题2:在遍历路由列表时,调用的func(),是原来的函数还是装饰器的内部函数???
答:原来函数,因为 route_list.append((path, func))追加的是func是原来的函数的地址。这个与装饰器没有啥关系。
5:显示股票信息页面的开发。
此时我们不再使用时间模拟,而是真正的访问数据库获取数据。
思路:连接数据库,获取游标,查询数据返回结果,循环遍历结果,与便签配合组合成前端页面内容,特换网页中的content数据,然后返回给web服务器。
# 获取首页数据
@route("/index.html")
def index():
# 响应状态
status = "200 OK";
# 响应头
response_header = [("Server", "PWS2.0")]
# 打开模板文件,读取数据
with open("template/index.html", "r") as file:
file_data = file.read()
# 处理后的数据, 从数据库查询
conn = pymysql.connect(host="localhost",
port=3306,
user="root",
password="123456",
database="stock_db",
charset="utf8")
# 获取游标
cursor = conn.cursor()
# 查询sql语句
sql = "select * from info;"
# 执行sql
cursor.execute(sql)
# 获取结果集,fetchall获取的是元组套元组的格式
result = cursor.fetchall()
print(result)
data = ""
# 此时的row是个元组
for row in result:
data += '''<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td><input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="000007"></td>
</tr>''' % row
# 替换模板文件中的模板遍历
result = file_data.replace("{%content%}", data)
return status, response_header, result
5:个人中心数据接口开发:
问题:刚才代码,后端做了前端的工作,属于前后端不分离开发,而更普遍的是前后端分离开发。

思路:浏览器访问center.html的时候,web框架先返回一个模板文件,然后浏览器获得模板文件后,js发送ajax请求(访问center_data.html),web框架再查询数据库,把数据以json的格式发送给浏览器,然后浏览器自己再通过js自己完成数据的填充。
# 个人中心数据接口开发
@route("/center_data.html")
def center_data():
# 响应状态
status = "200 OK";
# 响应头
response_header = [("Server", "PWS2.0"), ("Content-Type", "text/html;charset=utf-8")]
conn = pymysql.connect(host="localhost",
port=3306,
user="root",
password="123456",
database="stock_db",
charset="utf8")
# 获取游标
cursor = conn.cursor()
# 查询sql语句
sql = '''select i.code, i.short, i.chg,
i.turnover, i.price, i.highs, f.note_info
from info as i inner join focus as f on i.id = f.info_id;'''
# 执行sql
cursor.execute(sql)
# 获取结果集
result = cursor.fetchall()
# 关闭游标
cursor.close()
# 关闭数据库连接
conn.close()
# 个人中心数据列表
center_data_list = list()
# 遍历每一行数据转成字典
for row in result:
# 创建空的字典
center_dict = dict()
center_dict["code"] = row[0]
center_dict["short"] = row[1]
center_dict["chg"] = row[2]
center_dict["turnover"] = row[3]
center_dict["price"] = str(row[4])
center_dict["highs"] = str(row[5])
center_dict["note_info"] = row[6]
# 添加每个字典信息
center_data_list.append(center_dict)
# 把列表字典转成json字符串, 并在控制台显示
json_str = json.dumps(center_data_list,ensure_ascii=False)
print(json_str)
return status, response_header, json_str
result是元组套元组的格式,row是元组的格式,center.dict是字典格式,center_data_list是列表套字典的格式。
问题1:response_header = [(“Server”, “PWS2.0”), (“Content-Type”, “text/html;charset=utf-8”)]必须指定第二行这个数据,因为浏览器如果接收响应的时候,没有这句话,默认按照自己的格式解析,那么就看不到中文数字了。
问题2: json_str = json.dumps(center_data_list,ensure_ascii=False),将列表转换成json格式用json.dump函数,函数内需要指定ensure_ascii=False,因为dump默认将中文解析成ASCII码的格式,所以要取消默认。
后端返回给前端json那前端如何操作??
$.get("center_data.html", function (data) {
var data_array = data;
// 获取table标签对象
var $table = $(".table")
for(var i = 0; i < data_array.length; i++){
// 获取每一条对象
var center_obj = data_array[i];
var row_html = '<tr>' +
'<td>'+ center_obj.code +'</td>' +
'<td>'+ center_obj.short +'</td>' +
'<td>'+ center_obj.chg +'</td>' +
'<td>'+ center_obj.turnover +'</td>' +
'<td>'+ center_obj.price +'</td>' +
'<td>'+ center_obj.highs +'</td>' +
'<td>'+ center_obj.note_info +'</td>' +
'<td><a type="button" class="btn btn-default btn-xs" href="/update/000007.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a></td><td><input type="button" value="删除" id="toDel" name="toDel" systemidvaule="000007"></td></tr>';
// 为table标签添加每一行组装的html数据
$table.append(row_html);
}
}, "json");
分析过程:浏览器发送请求center.html,下面的第一段代码进行处理,读取center.html返回给浏览器,浏览器解析center.html,其中的center.html页面中的js代码(下面第二段代码),给数据库发送ajax请求,$.get(“center_data.html”, function (data),服务器接收到ajax请求后,@route("/center_data.html")def center_data():调用这个函数,返回给浏览器一个json数据,再次交给js,最后js搞定页面的填充。
@route("/center.html")
def center():
# 响应状态
status = "200 OK";
# 响应头
response_header = [("Server", "PWS2.0")]
# 打开模板文件,读取数据
with open("template/center.html", "r") as file:
file_data = file.read()
# # 处理后的数据, 从数据库查询
# data = time.ctime()
# 替换模板文件中的模板遍历
result = file_data.replace("{%content%}", "")
return status, response_header, result
$.get("center_data.html", function (data) {
var data_array = data;
获取table标签对象
var $table = $(".table")
for(var i = 0; i < data_array.length; i++){
// 获取每一条对象
var center_obj = data_array[i];
var row_html = '<tr>' +
'<td>'+ center_obj.code +'</td>' +
'<td>'+ center_obj.short +'</td>' +
'<td>'+ center_obj.chg +'</td>' +
'<td>'+ center_obj.turnover +'</td>' +
'<td>'+ center_obj.price +'</td>' +
'<td>'+ center_obj.highs +'</td>' +
'<td>'+ center_obj.note_info +'</td>' +
'<td><a type="button" class="btn btn-default btn-xs" href="/update/000007.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a></td><td><input type="button" value="删除" id="toDel" name="toDel" systemidvaule="000007"></td></tr>';
// 为table标签添加每一行组装的html数据
$table.append(row_html);
}
}, "json");
# 个人中心数据接口开发
@route("/center_data.html")
def center_data():
# 响应状态
status = "200 OK";
# 响应头
response_header = [("Server", "PWS2.0"), ("Content-Type", "text/html;charset=utf-8")]
conn = pymysql.connect(host="localhost",
port=3306,
user="root",
password="123456",
database="stock_db",
charset="utf8")
# 获取游标
cursor = conn.cursor()
# 查询sql语句
sql = '''select i.code, i.short, i.chg,
i.turnover, i.price, i.highs, f.note_info
from info as i inner join focus as f on i.id = f.info_id;'''
# 执行sql
cursor.execute(sql)
# 获取结果集
result = cursor.fetchall()
# 关闭游标
cursor.close()
# 关闭数据库连接
conn.close()
# 个人中心数据列表
center_data_list = list()
# 遍历每一行数据转成字典
for row in result:
# 创建空的字典
center_dict = dict()
center_dict["code"] = row[0]
center_dict["short"] = row[1]
center_dict["chg"] = row[2]
center_dict["turnover"] = row[3]
center_dict["price"] = str(row[4])
center_dict["highs"] = str(row[5])
center_dict["note_info"] = row[6]
# 添加每个字典信息
center_data_list.append(center_dict)
# 把列表字典转成json字符串, 并在控制台显示
json_str = json.dumps(center_data_list,ensure_ascii=False)
print(json_str)
return status, response_header, json_str
浙公网安备 33010602011771号