• 使用web框架程序处理客户端的动态资源请求代码实现


    一、web框架

    web框架:专门负责处理用户的动态资源请求,是一个为web服务器提供服务的应用程序

    web服务器接收浏览器发起的请求,若为动态资源请求则由web框架来处理,web框架负责处理浏览器的动态资源请求,并将处理结果发送给web服务器,web服务器再将处理结果组装为响应报文发送给浏览器

    • 静态资源:无需经常变化的资源,该类资源web服务器可以提前准备好,如png、jpg、css、js等文件
    • 动态资源:与静态资源相反,该类资源会经常变化,web服务器无法提前准备,需要web框架来帮web服务器准备,.html的资源请求可认为是web服务器将动态资源请求交由web框架进行处理
    • WSGI协议:是web服务器和web框架间进行协同工作的一个规则,其规定web服务器将动态资源的请求信息传给web框架处理,web框架把处理好的结果返回给web服务器

    二、框架程序代码

    框架职责:接收web服务器的动态资源请求,为web服务器提供处理动态资源请求的服务

    动态资源判断,根据请求资源路径的后缀名判断

    • 若后缀名为.html则为动态资源请求,让web框架程序进行处理
    • 否则为静态资源请求,让web服务器程序进行处理

    使用web框架程序处理客户端的动态资源请求操作代码

    webServer.py文件如下 

    1. import socket
    2. import threading
    3. import sys
    4. import webFrame
    5. class HttpWebServer(object):
    6. def __init__(self, port):
    7. server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建服务端套接字
    8. server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 设置端口号复用,程序退出端口立即释放
    9. server_socket.bind(("", port))
    10. server_socket.listen(128)
    11. self.server_socket = server_socket
    12. @staticmethod # 处理客户端请求
    13. def handle_client_request(comm_socket):
    14. recv_data = comm_socket.recv(4096) # 接收请求的二进制数据
    15. if len(recv_data) == 0:
    16. print('未获取到请求数据!')
    17. comm_socket.close()
    18. return
    19. recv_content = recv_data.decode('utf-8') # 对二进制数据解码
    20. print('获取到的数据内容为:', recv_content)
    21. request_list = recv_content.split(" ", maxsplit=2) # 根据指定字符串进行分割,最大分割次数为2
    22. request_path = request_list[1] # 获取请求资源路径
    23. print('请求路径为:', request_path)
    24. print('是否为/根目录:', request_path == "/")
    25. if request_path == "/": # 判断请求的是否是根目录,若是则返回首页指定数据
    26. request_path = "/index.html"
    27. if request_path.endswith(".html"): # 判断是否是动态资源请求
    28. # 动态资源请求需找web框架进行处理,把请求参数给webFrame框架
    29. # 准备需要给webFrame框架的参数信息,放在以下env字典中
    30. env = { # 字典存储用户的请求信息
    31. "request_path": request_path
    32. # 还可传入其他请求信息,如请求头
    33. }
    34. # web服务器获取webFrame框架处理结果
    35. print('拆包前:', webFrame.handle_request(env)) # 元组,结果为-拆包前:('200 OK 成功状态!', [('Server', 'PWS2.0')], 'Fri Nov 11 16:05:37 2022')
    36. status, headers, response_body = webFrame.handle_request(env) # 拆包获取处理结果,将字典中参数传入,使用webFrame框架处理动态资源请求
    37. print('拆包后status, headers, response_body分别为:', status, headers, response_body)
    38. # web服务器将webFrame框架返回的结果封装为响应报文发送给浏览器
    39. response_line = "HTTP/1.1 %s\r\n" % status # 响应行
    40. response_header = "" # 响应头
    41. for header in headers: # 遍历头部信息,响应头为一个列表,此处的headers为[('Server', 'PWS2.0')]
    42. response_header += "%s: %s\r\n" % (header[0], header[1]) # 拼接多个响应头,header为元组('Server', 'PWS2.0')
    43. response_data = (response_line + response_header + '\r\n' + response_body).encode('utf-8')
    44. comm_socket.send(response_data) # 发送响应报文数据给浏览器
    45. comm_socket.close()
    46. else: # 静态资源请求
    47. try:
    48. with open('C:/Users/username/Desktop/ubuntu' + request_path, 'rb') as file: # 动态打开指定文件
    49. file_data = file.read() # 读取指定文件数据
    50. except Exception as e: # 请求异常,资源不存在,返回指定404错误数据
    51. with open('C:/Users/username/Desktop/ubuntu/error.html', 'rb') as file: # 打开指定错误文件
    52. error_data = file.read() # 读取指定错误数据
    53. response_line = "HTTP/1.1 404 Not Found!!\r\n" # 响应行
    54. response_header = "Server: PWS1.0 服务器名称及版本……\r\n" # 响应头
    55. response_body = error_data # 响应体
    56. response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body # 拼接响应报文
    57. comm_socket.send(response_data) # 发送数据给浏览器
    58. else:
    59. response_line = "HTTP/1.1 200 OK # 成功!!\r\n"
    60. response_header = "Server: PWS1.0 # 服务器名称版本!\r\n"
    61. response_body = file_data
    62. response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
    63. comm_socket.send(response_data)
    64. finally:
    65. comm_socket.close() # 关闭服务于客户端的套接字
    66. def start(self):
    67. while True:
    68. comm_socket, ip_port = self.server_socket.accept() # 等待接收客户端连接请求
    69. print('comm_socket, ip_port值为:', comm_socket, '和', ip_port)
    70. thread = threading.Thread(target=self.handle_client_request, args=(comm_socket,))
    71. thread.daemon = True
    72. thread.start()
    73. def main():
    74. # 命令行方式执行
    75. # if len(sys.argv) != 2: # 判断命令行参数个数是否为2
    76. # print("请执行格式为[ python3 xx.py 9000 ] 的命令")
    77. # return
    78. # if not sys.argv[1].isdigit(): # 判断字符串是否为数字组成
    79. # print("请执行格式为[ python3 xx.py 9000 ]的命令")
    80. # return
    81. # port = int(sys.argv[1]) # 获取终端命令行参数
    82. # web_server = HttpWebServer(port)
    83. # 指定端口
    84. web_server = HttpWebServer(9000)
    85. web_server.start()
    86. if __name__ == '__main__':
    87. main()

    webFrame.py文件如下

    1. import time # miniweb框架,否则处理动态资源请求
    2. def index(): # 获取首页数据
    3. status = "200 OK 成功状态!" # 响应状态
    4. response_header = [("Server", "PWS2.0")] # 响应头
    5. data = time.ctime() # 处理后的数据,获取返回当前时间
    6. return status, response_header, data
    7. def notFound(): # 没有找到动态资源请求
    8. status = "404 not found 资源不存在"
    9. response_header = [("server"), "pws2.0"]
    10. data = "not found"
    11. return status, response_header, data
    12. def handle_request(env): # 处理动态资源请求
    13. request_path = env["request_path"] # 通过key关键字request_path获取值
    14. print("接收到的动态资源请求路径为:", request_path)
    15. if request_path == "/index.html":
    16. result = index() # 获取首页数据
    17. return result # 把处理后的结果返回给web服务器,用于web服务器拼接响应报文
    18. else:
    19. result = notFound()
    20. return result

     浏览器刷新后,正确请求输出

    1. 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)
    2. 获取到的数据内容为: GET /index.html HTTP/1.1
    3. Host: localhost:9000
    4. Connection: keep-alive
    5. Cache-Control: max-age=0
    6. sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"
    7. sec-ch-ua-mobile: ?0
    8. sec-ch-ua-platform: "Windows"
    9. Upgrade-Insecure-Requests: 1
    10. 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
    11. 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
    12. Sec-Fetch-Site: none
    13. Sec-Fetch-Mode: navigate
    14. Sec-Fetch-User: ?1
    15. Sec-Fetch-Dest: document
    16. Accept-Encoding: gzip, deflate, br
    17. Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    18. Cookie: Pycharm-cfdf024e=91ec719f-5cde-4808-99cd-9be6a1c1fec2; _ga=GA1.1.717883348.1658225866; Hm_lvt_18f619820855042bca58b32408f44de7=1658975947,1659083034,1660442096,1660728985
    19. 请求路径为: /index.html
    20. 是否为/根目录: False
    21. 接收到的动态资源请求路径为: /index.html
    22. 拆包前: ('200 OK 成功状态!', [('Server', 'PWS2.0')], 'Fri Nov 11 16:34:26 2022')
    23. 接收到的动态资源请求路径为: /index.html
    24. 拆包后status, headers, response_body分别为: 200 OK 成功状态! [('Server', 'PWS2.0')] Fri Nov 11 16:34:26 2022

     错误请求输出

    1. 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)
    2. 获取到的数据内容为: GET /index1.html HTTP/1.1
    3. Host: localhost:9000
    4. ……
    5. ……
    6. 请求路径为: /index1.html
    7. 是否为/根目录: False
    8. 接收到的动态资源请求路径为: /index1.html
    9. 拆包前: ('404 not found 资源不存在', ['server', 'pws2.0'], 'not found')
    10. 接收到的动态资源请求路径为: /index1.html
    11. 拆包后status, headers, response_body分别为: 404 not found 资源不存在 ['server', 'pws2.0'] not found

    三、使用模拟数据替换模板变量

    webFrame.py文件中的index() 函数修改如下

    1. def index(): # 获取首页数据
    2. status = "200 OK 成功状态!" # 响应状态
    3. response_header = [("Server", "PWS2.0")] # 响应头
    4. with open("templates/index.html", "r", encoding='utf-8') as file: # 打开指定文件,读取文件中数据
    5. file_content = file.read()
    6. # 查询数据库,将模板变量{%Date%}替换为从数据库查询的数据,以下使用date模拟数据库内容
    7. date = time.ctime() # 处理后的数据,获取返回当前时间,模拟数据库内容
    8. response_body = file_content.replace("{%Date%}", date) # 使用当前时间date替换index.html中的{%Date%}
    9. return status, response_header, response_body

    templates/index.html文件如下 

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Responsetitle>
    6. head>
    7. <body>
    8. <h2>{%Date%}h2>
    9. TCP、Python、HTML,这里是响应体!
    10. body>
    11. html>

     浏览器刷新后输出如下

    1. 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)
    2. 获取到的数据内容为: GET /index.html HTTP/1.1
    3. Host: localhost:9000
    4. ……
    5. ……
    6. 请求路径为: /index.html
    7. 是否为/根目录: False
    8. 接收到的动态资源请求路径为: /index.html
    9. 拆包前: ('200 OK 成功状态!', [('Server', 'PWS2.0')], '\n\n\n \n Response\n\n\n

      Fri Nov 11 20:43:15 2022

      \nTCP、Python、HTML,这里是响应体!\n\n\n\n'
      )
    10. 接收到的动态资源请求路径为: /index.html
    11. 拆包后status, headers, response_body分别为: 200 OK 成功状态! [('Server', 'PWS2.0')] DOCTYPE html>
    12. <html lang="en">
    13. <head>
    14. <meta charset="UTF-8">
    15. <title>Responsetitle>
    16. head>
    17. <body>
    18. <h2>Fri Nov 11 20:43:15 2022h2>
    19. TCP、Python、HTML,这里是响应体!
    20. body>
    21. html>

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

  • 相关阅读:
    光学:薄透镜成像、景深
    基于Java毕业设计养老院管理系统源码+系统+mysql+lw文档+部署软件
    如何在几分钟内创建一个对话机器人?
    Java多种方法实现等待所有子线程完成再继续执行
    ES6初步了解生成器
    java-net-php-python-MES生产线控制系统计算机毕业设计程序
    bat批处理---实现输入指定拷贝文件
    使用 Python 简单地实现一个网站视频播放地址查询工具
    微信小程序解析HTML标签带有<p>?
    【云原生】手把手教你在arm64架构系统,安装kubernetes及适配kubevela
  • 原文地址:https://blog.csdn.net/qq_43874317/article/details/127800827