前言
系列文章目录
视频及资料和课件
链接:https://pan.baidu.com/s/1LCv_qyWslwB-MYw56fjbDg?pwd=1234
提取码:1234
1. web框架概述
1.1 web框架和web服务器的关系介绍
静态web服务器用于静态资源数据请求。
动态资源请求使用web框架专门负责处理,这个web框架其实就是一个为web服务器提供服务的应用程序,简称web框架。
关系说明:
- web服务器接收浏览器发起的请求,如果是动态资源请求找web框架来处理
- web框架负责处理浏览器的动态资源请求,把处理的结果发生给web服务器
- web服务器再把响应结果发生给浏览器
1.2 静态资源
不需要经常变化的资源,这种资源web服务器可以提前准备好,比如: png/jpg/css/js等文件。
1.3 动态资源
和静态资源相反, 这种资源会经常变化,比如: 我们在京东浏览商品时经常会根据条件进行筛选,选择不同条件, 浏览的商品就不同,这种资源web服务器无法提前准备好,需要web框架来帮web服务器进行准备,在这里web服务器可以把.html的资源请求认为是动态资源请求交由web框架进行处理。
1.4 WSGI协议
它是web服务器和web框架之间进行协同工作的一个规则,WSGI协议规定web服务器把动态资源的请求信息传给web框架处理,web框架把处理好的结果返回给web服务器。
2. 框架程序开发
2.1 框架职责介绍
接收web服务器的动态资源请求,给web服务器提供处理动态资源请求的服务。
2.2 静态web服务器
import socket import sys import threading # 定义web服务器类 class HttpWebServer(object): def __init__(self, port): # 创建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(('', port)) # 服务端套接字监听 tcp_server_socket.listen(128) # 将tcp服务端套接字对象作为属性 self.tcp_server_socket = tcp_server_socket # 启动web服务器进行工作 def start(self): # 循环等待客户端的连接 while True: # 等待接受客户端的连接请求 new_socket, ip_port = self.tcp_server_socket.accept() print(ip_port) # 客户端与服务端建立连接后,创建子线程 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_client_data = new_socket.recv(4096) # 判断客户端是否处于连接转态 if len(recv_client_data) == 0: new_socket.close() return # 对二进制数据进行解码 recv_client_content = recv_client_data.decode('utf-8') print(recv_client_content) # 对字符串进行分割,分割两次,因为访问的资源路径在第二个位置 request_list = recv_client_content.split(' ', maxsplit=2) # 获取请求资源地址 request_path = request_list[1] print('请求的资源地址为:', request_path) # 如果请求的资源地址为 '/', 默认为首页index.html if request_path == '/': request_path = '/index.html' try: # 打开读取需要发送给客户端的文件 with open('static' + request_path, 'rb') as f: # 读取文件数据 file_data = f.read() except Exception as e: # 打开错误页面 with open('static/error.html', 'rb') as f: # 读取文件数据 file_data = f.read() # 将读取的数据封装为http格式的数据 # 响应行 response_line = 'HTTP/1.1 404 Not Found\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 # 发送数据给客户端 new_socket.send(response_data) else: # 将读取的数据封装为http格式的数据 # 响应行 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 # 发送数据给客户端 new_socket.send(response_data) finally: # 关闭与客户端的套接字 new_socket.close() # 程序入口函数 def main(): print('服务器运行在9090端口...') # 创建web服务器对象 # 服务器运行的端口为 9090 web_server = HttpWebServer(9090) # 启动web服务器进行工作 web_server.start() # 判断是否为主模块 if __name__ == '__main__': main()
2.3 动态资源判断
根据请求资源路径的后缀名进行判断:
(1)如果请求资源路径的后缀名是.html则是动态资源请求, 让web框架程序进行处理。
(2)否则是静态资源请求,让web服务器程序进行处理。
静态web服务器:
# 如果请求的资源地址为 '/', 默认为首页index.html if request_path == '/': request_path = '/index.html' # 判断是动态资源请求还是静态资源请求, 后缀为.html的为动态资源请求 if request_path.endswith('.html'): # 动态资源请求 # 动态资源请求找web框架处理,需要把请求参数给web框架 # 准备给web框架的参数信息 # env 环境变量,WSGI协议规定给web框架的参数信息最好使用env命名 env = { 'request_path': request_path # 目前只传请求路径 # 需要传递其他的信息,可以在字典中添加 } # 使用框架处理动态资源请求 # 1. web框架需要把处理结果返回web服务器 # 2. web服务器负责把返回的结果封装成响应报文发送给浏览器 # web框架需要返回 响应状态信息、响应头、响应体 status, headers, response_body = framework.handle_request(env) # 将web框架处理的数据封装成响应报文 # 响应行 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) new_socket.close() else: # 静态资源请求 # 执行原先静态web服务器的代码 # 因为原先写的静态web服务器用于处理静态资源 try: ... except Exception as e: ... else: ... finally: ...
import socket import sys import threading # 导入web框架 import framework # 定义web服务器类 class HttpWebServer(object): def __init__(self, port): # 创建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(('', port)) # 服务端套接字监听 tcp_server_socket.listen(128) # 将tcp服务端套接字对象作为属性 self.tcp_server_socket = tcp_server_socket # 启动web服务器进行工作 def start(self): # 循环等待客户端的连接 while True: # 等待接受客户端的连接请求 new_socket, ip_port = self.tcp_server_socket.accept() print(ip_port) # 客户端与服务端建立连接后,创建子线程 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_client_data = new_socket.recv(4096) # 判断客户端是否处于连接转态 if len(recv_client_data) == 0: new_socket.close() return # 对二进制数据进行解码 recv_client_content = recv_client_data.decode('utf-8') print(recv_client_content) # 对字符串进行分割,分割两次,因为访问的资源路径在第二个位置 request_list = recv_client_content.split(' ', maxsplit=2) # 获取请求资源地址 request_path = request_list[1] print('请求的资源地址为:', request_path) # 如果请求的资源地址为 '/', 默认为首页index.html if request_path == '/': request_path = '/index.html' # 判断是动态资源请求还是静态资源请求, 后缀为.html的为动态资源请求 if request_path.endswith('.html'): # 动态资源请求 # 动态资源请求找web框架处理,需要把请求参数给web框架 # 准备给web框架的参数信息 # env 环境变量,WSGI协议规定给web框架的参数信息最好使用env命名 env = { 'request_path': request_path # 目前只传请求路径 # 需要传递其他的信息,可以在字典中添加 } # 使用框架处理动态资源请求 # 1. web框架需要把处理结果返回web服务器 # 2. web服务器负责把返回的结果封装成响应报文发送给浏览器 # web框架需要返回 响应状态信息、响应头、响应体 status, headers, response_body = framework.handle_request(env) # 将web框架处理的数据封装成响应报文 # 响应行 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) new_socket.close() else: # 静态资源请求 # 执行原先静态web服务器的代码 # 因为原先写的静态web服务器用于处理静态资源 try: # 打开读取需要发送给客户端的文件 with open('static' + request_path, 'rb') as f: # 读取文件数据 file_data = f.read() except Exception as e: # 打开错误页面 with open('static/error.html', 'rb') as f: # 读取文件数据 file_data = f.read() # 将读取的数据封装为http格式的数据 # 响应行 response_line = 'HTTP/1.1 404 Not Found\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 # 发送数据给客户端 new_socket.send(response_data) else: # 将读取的数据封装为http格式的数据 # 响应行 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 # 发送数据给客户端 new_socket.send(response_data) finally: # 关闭与客户端的套接字 new_socket.close() # 程序入口函数 def main(): print('服务器运行在9090端口...') # 创建web服务器对象 # 服务器运行的端口为 9090 web_server = HttpWebServer(9090) # 启动web服务器进行工作 web_server.start() # 判断是否为主模块 if __name__ == '__main__': main()
web框架:
"""web框架用于处理动态资源请求""" import time def index(): # 状态信息 status = '200 OK' # 响应头信息 # 这里使用列表套元组的方法存放信息,每个元组为一个信息 response_header = [('Server', 'PWS/1.1')] # web框架成立后的数据 # 获取当前时间 date_now = time.ctime() # 返回信息 # 返回的是元组 return status, response_header, date_now def not_found(): # 状态信息 status = '404 Not Found' # 响应头信息 # 这里使用列表套元组的方法存放信息,每个元组为一个信息 response_header = [('Server', 'PWS/1.1')] # web框架成立后的数据 date_now = 'Not Found' # 返回信息 # 返回的是元组 return status, response_header, date_now def handle_request(env): # 获取动态资源请求路径 request_path = env['request_path'] print('动态资源请求路径:', request_path) # 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求 if request_path == '/index.html': # 返回处理数据 return index() else: # 没有动态资源信息,返回404 return not_found()
3. 模板替换功能开发
模板功能需要实现能够将数据库中查询出来的数据添加到需要返回给浏览器的页面中。
web框架代码:
# 1. 打开指定模板文件,读取模板文件中的数据 with open('template/index.html', 'r') as f: f_data = f.read() # 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据 # web框架处理后的数据 # 获取当前时间,模拟从数据库中查询出来的数据 date_now = time.ctime() response_body = f_data.replace('{%content%}', date_now) # 返回信息 # 返回的是元组 return status, response_header, response_body
"""web框架用于处理动态资源请求""" import time def index(): # 状态信息 status = '200 OK' # 响应头信息 # 这里使用列表套元组的方法存放信息,每个元组为一个信息 response_header = [('Server', 'PWS/1.1')] # 1. 打开指定模板文件,读取模板文件中的数据 with open('template/index.html', 'r') as f: f_data = f.read() # 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据 # web框架处理后的数据 # 获取当前时间,模拟从数据库中查询出来的数据 date_now = time.ctime() response_body = f_data.replace('{%content%}', date_now) # 返回信息 # 返回的是元组 return status, response_header, response_body def not_found(): # 状态信息 status = '404 Not Found' # 响应头信息 # 这里使用列表套元组的方法存放信息,每个元组为一个信息 response_header = [('Server', 'PWS/1.1')] # web框架成立后的数据 date_now = 'Not Found' # 返回信息 # 返回的是元组 return status, response_header, date_now def handle_request(env): # 获取动态资源请求路径 request_path = env['request_path'] print('动态资源请求路径:', request_path) # 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求 if request_path == '/index.html': # 返回处理数据 return index() else: # 没有动态资源信息,返回404 return not_found()