Python——mini-web框架、logging日志
mini-web框架
准备文件
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HELLO</title>
</head>
<body>
<h1> HELLO world </h1>
</body>
</html>
favicon.ico
web_main.py
import socket
import threading
import framework
class HttpWebServer(object):
def __init__(self):
# 创建tcp服务端套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口号复用,程序退出端口号立即释放
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口号
tcp_server_socket.bind(("", 8000))
# 设置监听
tcp_server_socket.listen(128)
# 把tcp服务器的套接字作为web服务器对象的属性
self.tcp_server_socket = tcp_server_socket
# 启动服务器的方法
def start(self):
# 循环等待接收客户端的连接请求
while True:
# 等待接收客户端的请求
new_socket, ip_port = self.tcp_server_socket.accept()
# 代码执行到此,说明链接建立成功
sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,))
# 设置成为守护主线程
sub_thread.setDaemon(True)
# 启动子线程执行对应任务
sub_thread.start()
# 处理客户请求
@staticmethod
def handle_client_request(new_socket):
# 接收客户端的请求信息
recv_data = new_socket.recv(4906)
# 判断接受的数据长度是否为0
if recv_data == 0:
new_socket.close()
return
# 对二进制数据进行编码
recv_content = recv_data.decode("utf-8")
print(recv_content)
# 对数据按照空格进行分割 (maxsplit 分割次数)
request_list = recv_content.split(" ", maxsplit=2)
# 获取请求的资源路径
request_path = request_list[1]
print(request_path)
# 判断请求的是否是根目录,如果是返回设定信息
if request_path == "/":
request_path = "/index.html"
# 判断是否是动态资源请求,将后缀是.html的请求任务定为动态资源请求
if request_path.endswith(".html"):
"""动态资源请求"""
# 动态资源请求找web框架进行处理,需要补请求参数给web框架
# 准备给web框架的参数信息,都要放到字典中
env = {
"request_path": request_path,
# 传入请求头信息,额外的参数可以再字典里面再进行添加
}
# 使用框架处理动态资源请求
# 1. web框架需要把处理器结果返回web服务器
# 2. web服务器负责把返回的结果封装成响应报文发送给浏览器
status, headers, response_body = framework.handle_request(env)
# 响应行
response_line = f"HTTP/1.1 {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")
# 发送响应报文数据给浏览器
new_socket.send(response_data)
# 关闭连接
new_socket.close()
else:
"""静态资源请求"""
'''判断文件是否存在,方法一
os.path.exits("static/" + request_path)
'''
# 判断文件是否存在,方法二
try:
# 打开文件读取文件信息 rb兼容打开图片文件
with open("static" + request_path, "rb") as file: # 这里的file表示打开文件的对象
file_data = file.read()
# with open 省去open中的close关闭步骤
except Exception as c:
# 相应行
response_line = "HTTP/1.1 404 Not Found\r\n"
# 响应头
response_header = "Server: PWS/1.0\r\n"
# 读取404页面数据
with open("static/error.html", "rb") as file:
file_data = file.read()
# 响应体
response_body = file_data
# 把数据封装成http 响应报文格式的数据
response = (response_line + response_header + "\r\n").encode("utf-8") + response_body
# 发送给浏览器的响应报文数据
new_socket.send(response)
else:
# 相应行
response_line = "HTTP/1.1 200 OK\r\n"
# 响应头
response_header = "Server: PWS/1.0\r\n"
# 响应体
response_body = file_data
# 把数据封装成http 响应报文格式的数据
response = (response_line + response_header + "\r\n").encode("utf-8") + response_body
# 发送给浏览器的响应报文数据
new_socket.send(response)
finally:
# 关闭服务于客户端的套接字
new_socket.close()
def main():
# 创建web服务器
web_server = HttpWebServer()
# 启动服务器
web_server.start()
if __name__ == '__main__':
main()
framework.py
"""web框架的职责专门负责处理动态资源请求"""
import time
def index():
# 状态信息
status = "200 OK"
# 响应头信息
response_header = [("Server", "PWS/1.1")]
# 1. 打开指定模拟文件,读取模拟文件的数据
# with open("template/index.html", "rb") as file:
# file_data = file.read()
# 2. 查询数据库,模板里面的模板变量{%content%} 替换成以后数据库里面查询的数据
# web处理后的数据
# 获取当前时间
data = time.ctime()
# 返回数据,返回的是元组
return status, response_header, data
def not_found():
# 状态信息
status = "404 Not Found"
# 响应头信息
response_header = [("Server", "PWS/1.1")]
# web处理后的数据
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()
# 把处理后的结果返回给web服务器使用,让web服务器拼接响应报文使用
return result
else:
# 没有动态资源数据,返回404状态信息
result = not_found()
# 把处理后的结果返回给web服务器使用,让web服务器拼接响应报文使用
return result
logging日志
# logging 记录程序运行时的日志信息
import logging
# 设置logging日志的配置信息
# level 表示设置级别
# %(asctime)s 表示当前时间
# %(filename)s 表示程序文件名
# %(lineno)d 表示行号
# %(levelname)s 表示日志级别
# %(message)s 表示日志信息
logging.basicConfig(level=logging.DEBUG,
format="%(asctime)s-%(filename)s[lineno:%(lineno)d]-%(levelname)s-%(message)s",
filename="log.txt",
filemode="w") # "a" 追加日志信息 "w" 重新写入日志信息
logging.debug("我是一个debug级别的日志信息")
logging.info("我是一个info级别的日志信息")
logging.warning("我是一个warning级别的日志信息")
logging.error("我是一个error级别的日志信息")
logging.critical("我是一个critical级别的日志信息")