赞
踩
我们已经知道web服务器主要的作用是,接收用户的http请求,根据用户的请求返回不同的资源数据。但是之前我们学习的都是静态web服务器,返回的都是静态资源数据
静态资源:不需要经常变化的资源,这种资源web服务器可以提前准备好,如: html页面模板、png、jpg、css、js等文件。)
动态资源:html页面模板+数据
为了让服务器返回动态html页面文件,我们需要一个Web框架
web框架专门负责处理用户的动态资源请求,根据数据库更新页面数据,将模板+数据组合成动态网页返回。
Web框架其实就是一个为web服务器提供服务的应用程序。
WSGI全称Web Server Gateway Interface(Web服务器网关接口),或Python Web Server Gateway Interface
它是web服务器和web框架(或Python应用程序)之间进行协同工作的一个接口协议。
WSGI协议规定,web服务器需把动态资源的http请求报文转化WSGI协议格式,再传给web框架进行处理。
web框架处理好请求之后,再把html文件与数据进行组装,返回给web服务器。
web服务器得到动态页面的结果后,再封装http响应报文,返回给浏览器。
import socket import threading class MyWebServer(object): def __init__(self, port): """初始化:创建套接字""" self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.server_socket.bind(("localhost", port)) self.server_socket.listen(128) def start(self): """启动:建立连接,并开启子线程""" while True: new_socket, address = self.server_socket.accept() print("已连接", address, sep=" from ") sub_thread = threading.Thread(target=self.handle, args=(new_socket,), daemon=True) sub_thread.start() @staticmethod def handle(handle_socket): """利用子线程收发http格式数据""" request_data = handle_socket.recv(4096) if len(request_data) == 0: print("浏览器已断开连接...") handle_socket.close() return request_content = request_data.decode("utf-8") print(request_content) # 以\r\n分割各项信息 request_list = request_content.split("\r\n") # 提取请求的资源路径 request_line = request_list[0] request_line_list = request_line.split(" ") request_method, request_path, request_version = request_line_list # 首页 if request_path == "/": request_path = "/index.html" # 响应行与响应头信息置空 response_line = response_header = "" # 根据请求路径准备好响应行和响应体 try: with open("." + request_path, "rb") as request_file: response_body = request_file.read() except (FileExistsError, FileNotFoundError): response_line += f"{request_version} 404 Not Found\r\n" with open("./error.html", "rb") as request_file: response_body = request_file.read() else: response_line += f"{request_version} 200 OK\r\n" finally: # 准备好响应头信息 response_header += "Server: MyWebServer2.0\r\n" # 向浏览器发送响应报文 response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body handle_socket.send(response_data) # 断开与浏览器的连接 handle_socket.close() def main(): port = 8888 my_web_server = MyWebServer(port) my_web_server.start() if __name__ == "__main__": main()
如果请求的资源是html文件,我们就可以认为这是动态资源请求。需要把这个请求封装成WSGI协议要求的格式,并传给web框架处理。
WSGI协议要求服务器将请求报文的各项信息组合成一个字典environ,再传给web框架
environ={
"request-path":"..." #请求路径
#...(以键值对形式传传入其他请求头信息)
}
为了追求简单,我们就这里就只传请求路径
暂时先忽略framework的实现,我们假设在framework.py
中,有一个Framework类。
更新服务器的初始化代码
from framework import FrameWork
def __init__(self, port):
"""初始化:创建套接字;初始化web框架"""
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
self.server_socket.bind(("localhost", port))
self.server_socket.listen(128)
self.framework=Framework()
self.framework
负责处理动态资源请求(主要是html)。
如果请求的是html文件,就将请求信息分解为environ字典,并传给self.framework
用handle_request
处理。
处理完成后,web框架需要返回响应状态(status),响应头信息(headers,元组列表形式),响应体数据(response_body)。
服务器再根据这些信息拼接成http响应报文返回给浏览器。
如果请求的不是html文件,就让服务器行使其静态功能。
#........ if request_path == "/": request_path = "/index.html" # 动态资源html交给web框架处理 if request_path.endswith(".html"): environ = dict() environ["request_path"] = request_path status, headers, response_body = self.framework.handle_request(environ) response_line = f"{request_version} {status}\r\n" 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") handle_socket.send(response_data) # 断开与浏览器的连接 handle_socket.close() # 静态资源静态web服务器处理 else: response_line = response_header = "" .......
前面我们看到,framework的主要功能就是接受environ请求字典,返回对应响应状态(status),响应头信息(headers,元组形式),响应体数据(response_body)。
第一步,为了寻求简单,我们就让请求index.html时返回现在的时间,请求其他网页时404 not Found
import time class FrameWork(object): @staticmethod def __index(): """主页处理函数""" # 响应状态 status = "200 OK" # 响应头信息 response_header = [("Server", "MyWebServer2.0")] # 处理后的数据 response_data = time.ctime() return status, response_header, response_data @staticmethod def __not_found(): """未找到资源处理函数""" # 响应状态 status = "404 Not Found" # 响应头 response_header = [("Server", "PWS2.0")] # 处理后的数据 response_data = "not found" return status, response_header, response_data def handle_request(self, environ): """framework框架主处理函数""" # 获取动态请求资源路径 request_path = environ["request_path"] if request_path == "/index.html": # 获取首页数据 result = self.__index() return result else: # 没有找到动态资源 result = self.__not_found() return result
动态html=静态html(模板)+数据库数据
在html中,我们可以用{%content%}
这种形式的变量来标识需要动态替换的数据。这样的html,就可以称为模板。
如:
<!--index.html--> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>首页 - 个人选股系统 V5.87</title> <link href="/css/bootstrap.min.css" rel="stylesheet"> <script src="/js/jquery-1.12.4.min.js"></script> <script src="/js/bootstrap.min.js"></script> <script> $(document).ready(function(){ $("input[name='toAdd']").each(function(){ var currentAdd = $(this); currentAdd.click(function(){ code = $(this).attr("systemIdVaule"); alert("/add/" + code + ".html"); $.get("/add/" + code + ".html", function(data, status){ alert("数据: " + data + "\n状态: " + status); }); }); }); }); </script> </head> <body> <div class="navbar navbar-inverse navbar-static-top "> <div class="container"> <div class="navbar-header"> <button class="navbar-toggle" data-toggle="collapse" data-target="#mymenu"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a href="#" class="navbar-brand">选股系统</a> </div> <div class="collapse navbar-collapse" id="mymenu"> <ul class="nav navbar-nav"> <li class="active"><a href="">股票信息</a></li> <li><a href="/center.html">个人中心</a></li> </ul> </div> </div> </div> <div class="container"> <div class="container-fluid"> <table class="table table-hover"> <tr> <th>序号</th> <th>股票代码</th> <th>股票简称</th> <th>涨跌幅</th> <th>换手率</th> <th>最新价(元)</th> <th>前期高点</th> <th>前期高点日期</th> <th>添加自选</th> </tr> {%content%} </table> </div> </div> </body> </html>
我们可以用数据库中的数据更换html中的{%content%}
变量。
为了简单,这里直接用时间代替数据库数据来试试效果。
@staticmethod
def __index():
"""主页处理函数"""
# 响应状态
status = "200 OK"
# 响应头信息
response_header = [("Server", "MyWebServer2.0")]
# 处理后的数据
with open("../template/index.html", "r",encoding="utf-8") as file:
file_data = file.read()
time_data = time.ctime()
response_data = file_data.replace("{%content%}", time_data)
return status, response_header, response_data
目前我们只有处理请求index.html
的函数。为了处理请求center.html
的函数,我们可以再写一个center函数。
@staticmethod
def __center():
"""个人中心处理函数"""
# 响应状态
status = "200 OK"
# 响应头信息
response_header = [("Server", "MyWebServer2.0")]
# 处理后的数据
with open("../template/center.html", "r", encoding="utf-8") as file:
file_data = file.read()
time_data = time.ctime()
response_data = file_data.replace("{%content%}", time_data)
return status, response_header, response_data
def handle_request(self, environ): """framework框架主处理函数""" # 获取动态请求资源路径 request_path = environ["request_path"] if request_path == "/index.html": # 获取首页数据 result = self.__index() return result elif request_path == "/center.html": # 获取首页数据 result = self.__center() return result else: # 没有找到动态资源 result = self.__not_found() return result
但这样的话,handle_request的代码未免太冗杂了。尤其是页面很多的情况下。
我们可以创建一个路由列表,它由二元组组成,二元组代表(页面请求路径,对应处理函数)的映射。
def __init__(self):
self.route_list=[
("/index.html",self.__index),
("/center.html",self.__center)
]
def handle_request(environ):
"""framework框架主处理函数"""
request_path = environ["request_path"]
# 遍历路由列表,选择执行的函数
for path, func in self.route_list:
if request_path == path:
result = func()
return result
else:
# 没有找到动态资源
result = self.__not_found()
return result
这样的话,代码就简洁多了,再多页面也是一样。
我们只需创建处理不同页面请求的函数,并将请求路径与处理函数添加到路由列表中即可。
通过含参装饰器的相关知识,我们可以实现,在定义处理函数的时候,自动向路由列表内添加二元映射。
route_list=[]
def route(request_path):
def decorator(func):
route_list.append((request_path, func)) #这里在@时自动执行
def inner(func, *args, **kwargs):
result = func(*args, **kwargs)
return result
return inner
return decorator
class FrameWork(object):
def __init__(self):
self.route_list = route_list #由于是可变对象,self.route_list和全局变量route_list保持一致
@staticmethod
@route("/index.html") #自动添加映射("./index.html",Framework.__index)
def __index():
"""主页处理函数"""
#...
@staticmethod
@route("/center")
def __center():
"""主页处理函数"""
#...
create database gupiao; use database gupiao; CREATE TABLE `info` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `code` varchar(6) NOT NULL COMMENT '股票代码', `short` varchar(10) NOT NULL COMMENT '股票简称', `chg` varchar(10) NOT NULL COMMENT '涨跌幅', `turnover` varchar(255) NOT NULL COMMENT '换手率', `price` decimal(10,2) NOT NULL COMMENT '最新价', `highs` decimal(10,2) NOT NULL COMMENT '前期高点', `time` date DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=utf8; INSERT INTO `info` VALUES (1,'000007','全新好','10.01%','4.40%',16.05,14.60,'2017-07-18'),(2,'000036','华联控股','10.04%','10.80%',11.29,10.26,'2017-07-20'),(3,'000039','中集集团','1.35%','1.78%',18.07,18.06,'2017-06-28'),(4,'000050','深天马A','4.38%','4.65%',22.86,22.02,'2017-07-19'),(5,'000056','皇庭国际','0.39%','0.65%',12.96,12.91,'2017-07-20'),(6,'000059','华锦股份','3.37%','7.16%',12.26,12.24,'2017-04-11'),(7,'000060','中金岭南','1.34%','3.39%',12.08,11.92,'2017-07-20'),(8,'000426','兴业矿业','0.41%','2.17%',9.71,9.67,'2017-07-20'),(9,'000488','晨鸣纸业','6.30%','5.50%',16.37,15.59,'2017-07-10'),(10,'000528','柳工','1.84%','3.03%',9.42,9.33,'2017-07-19'),(11,'000540','中天金融','0.37%','5.46%',8.11,8.08,'2017-07-20'),(12,'000581','威孚高科','3.49%','3.72%',27.00,26.86,'2017-06-26'),(13,'000627','天茂集团','5.81%','12.51%',10.93,10.33,'2017-07-20'),(14,'000683','远兴能源','6.42%','21.27%',3.48,3.29,'2017-07-19'),(15,'000703','恒逸石化','0.24%','1.65%',16.92,16.88,'2017-07-20'),(16,'000822','山东海化','6.60%','8.54%',9.05,8.75,'2017-07-06'),(17,'000830','鲁西化工','1.38%','4.80%',7.36,7.26,'2017-07-20'),(18,'000878','云南铜业','1.26%','3.23%',14.50,14.47,'2017-07-19'),(19,'000905','厦门港务','5.44%','10.85%',15.90,15.60,'2017-04-20'),(20,'000990','诚志股份','0.53%','1.00%',16.99,16.90,'2017-07-20'),(21,'002019','亿帆医药','1.19%','2.81%',17.05,16.85,'2017-07-20'),(22,'002078','太阳纸业','2.05%','1.90%',8.45,8.29,'2017-07-19'),(23,'002092','中泰化学','7.25%','6.20%',15.53,14.48,'2017-07-20'),(24,'002145','中核钛白','2.43%','7.68%',6.75,6.61,'2017-07-19'),(25,'002285','世联行','8.59%','5.66%',9.23,8.50,'2017-07-20'),(26,'002311','海大集团','1.13%','0.24%',18.81,18.63,'2017-07-19'),(27,'002460','赣锋锂业','9.41%','9.00%',63.70,58.22,'2017-07-20'),(28,'002466','天齐锂业','3.62%','3.66%',68.44,66.05,'2017-07-20'),(29,'002470','金正大','2.30%','0.99%',8.00,7.82,'2017-07-20'),(30,'002496','辉丰股份','3.15%','4.29%',5.24,5.08,'2017-04-10'),(31,'002497','雅化集团','0.38%','12.36%',13.10,13.05,'2017-07-20'),(32,'002500','山西证券','0.44%','3.70%',11.49,11.44,'2017-07-20'),(33,'002636','金安国纪','2.70%','11.59%',19.80,19.42,'2017-07-19'),(34,'300032','金龙机电','0.66%','0.72%',15.28,15.18,'2017-07-20'),(35,'300115','长盈精密','0.60%','0.59%',33.50,33.41,'2017-07-19'),(36,'300268','万福生科','-10.00%','0.27%',31.77,13.57,'2017-04-10'),(37,'300280','南通锻压','3.31%','0.66%',32.20,32.00,'2017-04-11'),(38,'300320','海达股份','0.28%','0.82%',18.26,18.21,'2017-07-20'),(39,'300408','三环集团','1.69%','0.81%',23.42,23.17,'2017-07-19'),(40,'300477','合纵科技','2.84%','5.12%',22.10,22.00,'2017-07-12'),(41,'600020','中原高速','5.46%','4.48%',5.60,5.31,'2017-07-20'),(42,'600033','福建高速','1.01%','1.77%',4.00,3.99,'2017-06-26'),(43,'600066','宇通客车','4.15%','1.49%',23.08,23.05,'2017-06-13'),(44,'600067','冠城大通','0.40%','2.97%',7.56,7.53,'2017-07-20'),(45,'600110','诺德股份','2.08%','4.26%',16.16,15.83,'2017-07-20'),(46,'600133','东湖高新','9.65%','21.74%',13.64,12.44,'2017-07-20'),(47,'600153','建发股份','3.65%','2.03%',13.35,13.21,'2017-07-10'),(48,'600180','瑞茂通','2.20%','1.07%',14.86,14.54,'2017-07-20'),(49,'600183','生益科技','6.94%','4.06%',14.94,14.12,'2017-07-19'),(50,'600188','兖州煤业','1.53%','0.99%',14.56,14.43,'2017-07-19'),(51,'600191','华资实业','10.03%','11.72%',15.80,14.36,'2017-07-20'),(52,'600210','紫江企业','6.03%','10.90%',6.68,6.30,'2017-07-20'),(53,'600212','江泉实业','1.39%','1.78%',10.20,10.15,'2017-07-19'),(54,'600225','*ST松江','4.96%','2.47%',5.71,5.61,'2017-04-13'),(55,'600230','沧州大化','5.74%','13.54%',43.26,40.91,'2017-07-20'),(56,'600231','凌钢股份','2.79%','3.77%',3.68,3.60,'2017-07-19'),(57,'600291','西水股份','10.02%','9.23%',34.71,31.55,'2017-07-20'),(58,'600295','鄂尔多斯','4.96%','12.62%',16.51,15.73,'2017-07-20'),(59,'600303','曙光股份','8.37%','14.53%',11.53,10.64,'2017-07-20'),(60,'600308','华泰股份','1.12%','2.66%',6.30,6.26,'2017-07-19'),(61,'600309','万华化学','0.03%','1.78%',31.81,31.80,'2017-07-20'),(62,'600352','浙江龙盛','0.39%','1.85%',10.32,10.28,'2017-07-20'),(63,'600354','敦煌种业','7.89%','18.74%',9.44,8.75,'2017-07-20'),(64,'600408','安泰集团','1.98%','3.38%',4.13,4.12,'2017-04-13'),(65,'600409','三友化工','0.62%','3.78%',11.36,11.29,'2017-07-20'),(66,'600499','科达洁能','0.46%','3.94%',8.84,8.80,'2017-07-20'),(67,'600508','上海能源','3.26%','2.99%',13.32,13.01,'2017-07-19'),(68,'600563','法拉电子','0.32%','1.36%',53.67,53.50,'2017-07-20'),(69,'600567','山鹰纸业','0.76%','2.85%',3.98,3.96,'2017-07-19'),(70,'600585','海螺水泥','0.45%','0.61%',24.51,24.44,'2017-07-19'),(71,'600668','尖峰集团','4.35%','6.43%',18.70,18.36,'2017-04-13'),(72,'600688','上海石化','2.72%','0.91%',6.80,6.74,'2017-06-01'),(73,'600729','重庆百货','5.70%','3.34%',27.45,27.13,'2017-06-29'),(74,'600739','辽宁成大','3.30%','3.50%',19.74,19.11,'2017-07-20'),(75,'600779','水井坊','3.85%','2.77%',29.39,28.30,'2017-07-20'),(76,'600781','辅仁药业','8.61%','4.16%',23.46,21.89,'2017-05-02'),(77,'600801','华新水泥','4.00%','10.15%',12.99,12.49,'2017-07-20'),(78,'600846','同济科技','2.06%','17.41%',9.39,9.26,'2017-04-13'),(79,'600884','杉杉股份','1.08%','3.53%',20.67,20.45,'2017-07-20'),(80,'600966','博汇纸业','2.89%','5.54%',6.41,6.28,'2017-07-19'),(81,'600971','恒源煤电','2.36%','8.81%',12.16,11.88,'2017-07-20'),(82,'601012','隆基股份','0.76%','1.30%',19.93,19.78,'2017-07-20'),(83,'601100','恒立液压','4.78%','0.92%',19.31,18.97,'2017-07-13'),(84,'601101','昊华能源','4.03%','6.06%',11.10,10.80,'2017-07-19'),(85,'601216','君正集团','2.16%','2.26%',5.20,5.10,'2017-04-17'),(86,'601666','平煤股份','2.81%','6.14%',6.96,6.77,'2017-07-20'),(87,'601668','中国建筑','2.39%','1.42%',10.70,10.45,'2017-07-20'),(88,'601678','滨化股份','0.13%','2.47%',7.92,7.91,'2017-07-20'),(89,'601918','新集能源','1.23%','3.11%',4.93,4.92,'2017-07-19'),(90,'603167','渤海轮渡','2.77%','3.34%',11.87,11.61,'2017-04-13'),(91,'603369','今世缘','3.34%','2.13%',14.24,13.78,'2017-07-20'),(92,'603589','口子窖','3.99%','1.84%',39.37,39.04,'2017-06-26'),(93,'603799','华友钴业','2.38%','7.19%',67.46,65.89,'2017-07-20'),(94,'603993','洛阳钼业','2.94%','2.50%',7.36,7.16,'2017-07-19'); CREATE TABLE `focus` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `note_info` varchar(200) DEFAULT '', `info_id` int(10) unsigned DEFAULT NULL, PRIMARY KEY (`id`), KEY `info_id` (`info_id`), CONSTRAINT `focus_ibfk_1` FOREIGN KEY (`info_id`) REFERENCES `info` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 INSERT INTO `focus` VALUES (2,'你确定要买这个?',36),(3,'利好',37),(9,'',88),(10,'',89),(13,'',1);
以上sql语句建立了gupiao数据库和info,focus表
我们可以利用python的pymysql模块,查询数据库并用查询结果替换{%content%}
import pymysql #...... @staticmethod @route("/index.html") def __index(): """主页处理函数""" # 响应状态 status = "200 OK" # 响应头信息 response_header = [("Server", "MyWebServer2.0")] # 处理后的数据 with open("../template/index.html", "r", encoding="utf-8") as file: file_data = file.read() db_connect = pymysql.connect(host="localhost", port=3306, user="root", password="123", database="gupiao", charset="utf8") cursor = db_connect.cursor() sql = "select * from info;" cursor.execute(sql) result = cursor.fetchall() data = "" 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 # 替换模板文件中的模板变量 response_data = file_data.replace("{%content%}", data) return status, response_header, response_data
网页开发向来注重前后端分离。
后端提供数据支持,前端负责显示数据。
web框架程序可以开发数据接口,为浏览器提供数据服务。
数据接口一般是json文件
当请求路径是/center_data.html
时,返回一个json字符串,为浏览器提供数据接口。
浏览器获得数据接口后,可利用Ajax进行局部刷新。
@staticmethod @route("/center_data.html") def center_data(): """个人中心数据接口开发""" status = "200 OK" # 响应头 response_header = [("Server", "MyWebServer2.0"), ("Content-Type", "text/html;charset=utf-8")] db_connect = pymysql.connect(host="localhost", port=3306, user="root", password="123", database="gupiao", charset="utf8") cursor = db_connect.cursor() sql = ''' select info.code, info.short, info.chg, info.turnover,info.price,info.highs, info.note_info from info inner join focus on info.id = focus.info_id; ''' cursor.execute(sql) result = cursor.fetchall() cursor.close() db_connect.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) return status, response_header, json_str
一开始我们能够获取到center.html
,但这个页面中没有数据。
为了获取数据,我们可以在center.html
中加入Ajax代码,让浏览器去请求center_data.html
,获得个人中心数据,并局部渲染出这些数据项。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>个人中心 - 个人选股系统 V5.87</title> <link href="/css/bootstrap.min.css" rel="stylesheet"> <script src="/js/jquery-1.12.4.min.js"></script> <script src="/js/bootstrap.min.js"></script> <script> $(document).ready(function(){ // 发送ajax请求,获取个人中心数据 $.get("center_data.html",function (center_data) { // 获取table标签 var $table = $(".table"); // 如果指定了返回数据的解析方式是json,那么data就是一个js对象 for(var i = 0; i < center_data.length; i++){ //获取每一行的js对象 var $row = center_data[i]; // 准备每一行数据 var $rowStr = '<tr>' + '<td>'+ $row.code +'</td>' + '<td>'+ $row.short +'</td>' + '<td>'+ $row.chg +'</td>' + '<td>'+ $row.turnover +'</td>' + '<td>'+ $row.price +'</td>' + '<td>'+ $row.highs +'</td>' + '<td>'+ $row.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元素内追加数据 $table.append($rowStr) } }, "json"); $("input[name='toDel']").each(function(){ var currentAdd = $(this); currentAdd.click(function(){ code = $(this).attr("systemIdVaule"); alert("/del/" + code + ".html"); $.get("/del/" + code + ".html", function(data, status){ alert("数据: " + data + "\n状态: " + status); }); window.location.reload() }); }); }); </script> </head> <body> <div class="navbar navbar-inverse navbar-static-top "> <div class="container"> <div class="navbar-header"> <button class="navbar-toggle" data-toggle="collapse" data-target="#mymenu"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a href="#" class="navbar-brand">选股系统</a> </div> <div class="collapse navbar-collapse" id="mymenu"> <ul class="nav navbar-nav"> <li ><a href="./index.html">股票信息</a></li> <li class="active"><a href="./center.html">个人中心</a></li> </ul> </div> </div> </div> <div class="container"> <div class="container-fluid"> <table class="table table-hover"> <tr> <th>股票代码</th> <th>股票简称</th> <th>涨跌幅</th> <th>换手率</th> <th>最新价(元)</th> <th>前期高点</th> <th style="color:red">备注信息</th> <th>修改备注</th> <th>del</th> </tr> {%content%} </table> </div> </div> </body> </html>
日志信息可以记录服务器的运行状态和信息。
以下等级依次提高
import logging
logging.debug('调试中...')
logging.info('正常运行中...')
logging.warning('警告!')
logging.error('出现错误,继续运行...')
logging.critical('出现错误,程序奔溃!')
"""
WARNING:root:警告!
ERROR:root:出现错误,继续运行...
CRITICAL:root:出现错误,程序奔溃!
"""
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') logging.debug('调试中...') logging.info('正常运行中...') logging.warning('警告!') logging.error('出现错误,继续运行...') logging.critical('出现错误,程序奔溃!') """ 2022-06-29 16:09:47,604 - web_logging.py[line:5] - DEBUG: 调试中... 2022-06-29 16:09:47,604 - web_logging.py[line:6] - INFO: 正常运行中... 2022-06-29 16:09:47,604 - web_logging.py[line:7] - WARNING: 警告! 2022-06-29 16:09:47,604 - web_logging.py[line:8] - ERROR: 出现错误,继续运行... 2022-06-29 16:09:47,604 - web_logging.py[line:9] - CRITICAL: 出现错误,程序奔溃! """
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s',
filename="log.txt",
filemode="w")
import socket import threading import logging from framework import FrameWork # logging日志的配置 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', filename="log.txt", filemode="w") class MyWebServer(object): def __init__(self, port): """初始化:创建套接字;初始化web框架""" self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.server_socket.bind(("localhost", port)) self.server_socket.listen(128) self.framework = FrameWork() def start(self): """启动:建立连接,并开启子线程""" while True: new_socket, address = self.server_socket.accept() logging.info(f"接受来自{address}的连接") sub_thread = threading.Thread(target=self.handle, args=(new_socket,), daemon=True) sub_thread.start() def handle(self, handle_socket): """利用子线程收发http格式数据""" request_data = handle_socket.recv(4096) if len(request_data) == 0: logging.info("浏览器已断开连接") handle_socket.close() return request_content = request_data.decode("utf-8") print(request_content) # 以\r\n分割各项信息 request_list = request_content.split("\r\n") # 提取请求的资源路径 request_line = request_list[0] request_line_list = request_line.split(" ") request_method, request_path, request_version = request_line_list # 首页 if request_path == "/": request_path = "/index.html" # 动态资源html交给web框架处理 if request_path.endswith(".html"): logging.info("动态资源请求:" + request_path) environ = dict() environ["request_path"] = request_path status, headers, response_body = self.framework.handle_request(environ) response_line = f"{request_version} {status}\r\n" 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") handle_socket.send(response_data) # 断开与浏览器的连接 handle_socket.close() # 静态资源静态web服务器处理 else: logging.info("静态资源请求:" + request_path) response_line = response_header = "" # 根据请求路径准备好响应行和响应体 try: with open("." + request_path, "rb") as request_file: response_body = request_file.read() except (FileExistsError, FileNotFoundError): response_line += f"{request_version} 404 Not Found\r\n" with open("./error.html", "rb") as request_file: response_body = request_file.read() else: response_line += f"{request_version} 200 OK\r\n" finally: # 准备好响应头信息 response_header += "Server: MyWebServer2.0\r\n" # 向浏览器发送响应报文 response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body handle_socket.send(response_data) # 断开与浏览器的连接 handle_socket.close() def main(): port = 8888 my_web_server = MyWebServer(port) my_web_server.start() if __name__ == "__main__": main()
import time import pymysql import json import logging route_list = [] def route(request_path): def decorator(func): route_list.append((request_path, func)) def inner(func, *args, **kwargs): result = func(*args, **kwargs) return result return inner return decorator class FrameWork(object): def __init__(self): self.route_list = route_list @staticmethod @route("/index.html") def __index(): """主页处理函数""" # 响应状态 status = "200 OK" # 响应头信息 response_header = [("Server", "MyWebServer2.0")] # 处理后的数据 with open("../template/index.html", "r", encoding="utf-8") as file: file_data = file.read() db_connect = pymysql.connect(host="localhost", port=3306, user="root", password="s1234567890", database="gupiao", charset="utf8") # 获取游标 cursor = db_connect.cursor() # 查询sql语句 sql = "select * from info;" # 执行sql cursor.execute(sql) # 获取结果集 result = cursor.fetchall() data = "" 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 # 替换模板文件中的模板遍历 response_data = file_data.replace("{%content%}", data) return status, response_header, response_data @staticmethod @route("/center.html") def __center(): """个人中心处理函数""" # 响应状态 status = "200 OK" # 响应头信息 response_header = [("Server", "MyWebServer2.0")] # 处理后的数据 with open("../template/center.html", "r", encoding="utf-8") as file: file_data = file.read() time_data = time.ctime() response_data = file_data.replace("{%content%}", time_data) return status, response_header, response_data @staticmethod def __not_found(): """未找到资源处理函数""" # 响应状态 status = "404 Not Found" # 响应头 response_header = [("Server", "PWS2.0")] # 处理后的数据 response_data = "not found" return status, response_header, response_data @staticmethod @route("/center_data.html") def center_data(): """个人中心数据接口开发""" status = "200 OK" response_header = [("Server", "MyWebServer2.0"), ("Content-Type", "text/html;charset=utf-8")] conn = pymysql.connect(host="localhost", port=3306, user="root", password="s1234567890", database="gupiao", charset="utf8") cursor = conn.cursor() 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; ''' 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) return status, response_header, json_str def handle_request(self, environ): """framework框架主处理函数""" # 获取动态请求资源路径 request_path = environ["request_path"] for path, func in route_list: if request_path == path: result = func() return result else: # 没有找到动态资源 logging.error("没有设置相应的路由:" + request_path) result = self.__not_found() return result
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。