web框架:专门负责处理用户的动态资源请求,是一个为web服务器提供服务的应用程序
web服务器接收浏览器发起的请求,若为动态资源请求则由web框架来处理,web框架负责处理浏览器的动态资源请求,并将处理结果发送给web服务器,web服务器再将处理结果组装为响应报文发送给浏览器
框架职责:接收web服务器的动态资源请求,为web服务器提供处理动态资源请求的服务
动态资源判断,根据请求资源路径的后缀名判断
使用web框架程序处理客户端的动态资源请求操作代码
webServer.py文件如下
- import socket
- import threading
- import sys
- import webFrame
-
- class HttpWebServer(object):
- def __init__(self, port):
- server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建服务端套接字
- server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 设置端口号复用,程序退出端口立即释放
- server_socket.bind(("", port))
- server_socket.listen(128)
- self.server_socket = server_socket
-
- @staticmethod # 处理客户端请求
- def handle_client_request(comm_socket):
- recv_data = comm_socket.recv(4096) # 接收请求的二进制数据
- if len(recv_data) == 0:
- print('未获取到请求数据!')
- comm_socket.close()
- return
- recv_content = recv_data.decode('utf-8') # 对二进制数据解码
- print('获取到的数据内容为:', recv_content)
- request_list = recv_content.split(" ", maxsplit=2) # 根据指定字符串进行分割,最大分割次数为2
- request_path = request_list[1] # 获取请求资源路径
- print('请求路径为:', request_path)
- print('是否为/根目录:', request_path == "/")
-
- if request_path == "/": # 判断请求的是否是根目录,若是则返回首页指定数据
- request_path = "/index.html"
-
- if request_path.endswith(".html"): # 判断是否是动态资源请求
- # 动态资源请求需找web框架进行处理,把请求参数给webFrame框架
-
- # 准备需要给webFrame框架的参数信息,放在以下env字典中
- env = { # 字典存储用户的请求信息
- "request_path": request_path
- # 还可传入其他请求信息,如请求头
- }
-
- # web服务器获取webFrame框架处理结果
- print('拆包前:', webFrame.handle_request(env)) # 元组,结果为-拆包前:('200 OK 成功状态!', [('Server', 'PWS2.0')], 'Fri Nov 11 16:05:37 2022')
- status, headers, response_body = webFrame.handle_request(env) # 拆包获取处理结果,将字典中参数传入,使用webFrame框架处理动态资源请求
- print('拆包后status, headers, response_body分别为:', status, headers, response_body)
-
- # web服务器将webFrame框架返回的结果封装为响应报文发送给浏览器
- response_line = "HTTP/1.1 %s\r\n" % status # 响应行
- response_header = "" # 响应头
- for header in headers: # 遍历头部信息,响应头为一个列表,此处的headers为[('Server', 'PWS2.0')]
- response_header += "%s: %s\r\n" % (header[0], header[1]) # 拼接多个响应头,header为元组('Server', 'PWS2.0')
- response_data = (response_line + response_header + '\r\n' + response_body).encode('utf-8')
- comm_socket.send(response_data) # 发送响应报文数据给浏览器
- comm_socket.close()
-
- else: # 静态资源请求
- try:
- with open('C:/Users/username/Desktop/ubuntu' + request_path, 'rb') as file: # 动态打开指定文件
- file_data = file.read() # 读取指定文件数据
- except Exception as e: # 请求异常,资源不存在,返回指定404错误数据
- with open('C:/Users/username/Desktop/ubuntu/error.html', 'rb') as file: # 打开指定错误文件
- error_data = file.read() # 读取指定错误数据
- response_line = "HTTP/1.1 404 Not Found!!\r\n" # 响应行
- response_header = "Server: PWS1.0 服务器名称及版本……\r\n" # 响应头
- response_body = error_data # 响应体
- response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body # 拼接响应报文
- comm_socket.send(response_data) # 发送数据给浏览器
- else:
- response_line = "HTTP/1.1 200 OK # 成功!!\r\n"
- response_header = "Server: PWS1.0 # 服务器名称版本!\r\n"
- response_body = file_data
- response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
- comm_socket.send(response_data)
- finally:
- comm_socket.close() # 关闭服务于客户端的套接字
- def start(self):
- while True:
- comm_socket, ip_port = self.server_socket.accept() # 等待接收客户端连接请求
- print('comm_socket, ip_port值为:', comm_socket, '和', ip_port)
- thread = threading.Thread(target=self.handle_client_request, args=(comm_socket,))
- thread.daemon = True
- thread.start()
- def main():
- # 命令行方式执行
- # if len(sys.argv) != 2: # 判断命令行参数个数是否为2
- # print("请执行格式为[ python3 xx.py 9000 ] 的命令")
- # return
- # if not sys.argv[1].isdigit(): # 判断字符串是否为数字组成
- # print("请执行格式为[ python3 xx.py 9000 ]的命令")
- # return
- # port = int(sys.argv[1]) # 获取终端命令行参数
- # web_server = HttpWebServer(port)
-
- # 指定端口
- web_server = HttpWebServer(9000)
- web_server.start()
- if __name__ == '__main__':
- main()
webFrame.py文件如下
- import time # miniweb框架,否则处理动态资源请求
- def index(): # 获取首页数据
- status = "200 OK 成功状态!" # 响应状态
- response_header = [("Server", "PWS2.0")] # 响应头
- data = time.ctime() # 处理后的数据,获取返回当前时间
- return status, response_header, data
- def notFound(): # 没有找到动态资源请求
- 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"] # 通过key关键字request_path获取值
- print("接收到的动态资源请求路径为:", request_path)
- if request_path == "/index.html":
- result = index() # 获取首页数据
- return result # 把处理后的结果返回给web服务器,用于web服务器拼接响应报文
- else:
- result = notFound()
- return result
浏览器刷新后,正确请求输出
- comm_socket, ip_port值为:
socket fd=304, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 55654)> 和 ('127.0.0.1', 55654) - 获取到的数据内容为: GET /index.html HTTP/1.1
- Host: localhost:9000
- Connection: keep-alive
- Cache-Control: max-age=0
- sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"
- sec-ch-ua-mobile: ?0
- sec-ch-ua-platform: "Windows"
- Upgrade-Insecure-Requests: 1
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*;q=0.8,application/signed-exchange;v=b3;q=0.9
- Sec-Fetch-Site: none
- Sec-Fetch-Mode: navigate
- Sec-Fetch-User: ?1
- Sec-Fetch-Dest: document
- Accept-Encoding: gzip, deflate, br
- Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
- Cookie: Pycharm-cfdf024e=91ec719f-5cde-4808-99cd-9be6a1c1fec2; _ga=GA1.1.717883348.1658225866; Hm_lvt_18f619820855042bca58b32408f44de7=1658975947,1659083034,1660442096,1660728985
-
-
- 请求路径为: /index.html
- 是否为/根目录: False
- 接收到的动态资源请求路径为: /index.html
- 拆包前: ('200 OK 成功状态!', [('Server', 'PWS2.0')], 'Fri Nov 11 16:34:26 2022')
- 接收到的动态资源请求路径为: /index.html
- 拆包后status, headers, response_body分别为: 200 OK 成功状态! [('Server', 'PWS2.0')] Fri Nov 11 16:34:26 2022

错误请求输出
- comm_socket, ip_port值为:
socket fd=324, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 56131)> 和 ('127.0.0.1', 56131) - 获取到的数据内容为: GET /index1.html HTTP/1.1
- Host: localhost:9000
- ……
- ……
-
- 请求路径为: /index1.html
- 是否为/根目录: False
- 接收到的动态资源请求路径为: /index1.html
- 拆包前: ('404 not found 资源不存在', ['server', 'pws2.0'], 'not found')
- 接收到的动态资源请求路径为: /index1.html
- 拆包后status, headers, response_body分别为: 404 not found 资源不存在 ['server', 'pws2.0'] not found

webFrame.py文件中的index() 函数修改如下
- def index(): # 获取首页数据
- status = "200 OK 成功状态!" # 响应状态
- response_header = [("Server", "PWS2.0")] # 响应头
- with open("templates/index.html", "r", encoding='utf-8') as file: # 打开指定文件,读取文件中数据
- file_content = file.read()
- # 查询数据库,将模板变量{%Date%}替换为从数据库查询的数据,以下使用date模拟数据库内容
- date = time.ctime() # 处理后的数据,获取返回当前时间,模拟数据库内容
- response_body = file_content.replace("{%Date%}", date) # 使用当前时间date替换index.html中的{%Date%}
- return status, response_header, response_body
templates/index.html文件如下
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Responsetitle>
- head>
- <body>
- <h2>{%Date%}h2>
- TCP、Python、HTML,这里是响应体!
- body>
- html>
浏览器刷新后输出如下
- comm_socket, ip_port值为:
socket fd=416, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 64561)> 和 ('127.0.0.1', 64561) - 获取到的数据内容为: GET /index.html HTTP/1.1
- Host: localhost:9000
- ……
- ……
-
- 请求路径为: /index.html
- 是否为/根目录: False
- 接收到的动态资源请求路径为: /index.html
- 拆包前: ('200 OK 成功状态!', [('Server', 'PWS2.0')], '\n\n\n \n
Response \n\n\nFri Nov 11 20:43:15 2022
\nTCP、Python、HTML,这里是响应体!\n\n\n\n') - 接收到的动态资源请求路径为: /index.html
- 拆包后status, headers, response_body分别为: 200 OK 成功状态! [('Server', 'PWS2.0')] DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Responsetitle>
- head>
- <body>
- <h2>Fri Nov 11 20:43:15 2022h2>
- TCP、Python、HTML,这里是响应体!
- body>
- html>

学习导航:http://xqnav.top/