0


开发自己的 Web 框架

  1. 开发自己的 Web 框架

接收web服务器的动态资源请求,给web服务器提供处理动态资源请求的服务。根据请求资源路径的后缀名进行判断

  • 如果请求资源路径的后缀名是.html则是动态资源请求,让web框架程序进行处理。
  • 否则是静态资源请求,让web服务器程序进行处理。

开发Web服务器主体程序

  1. 接受客户端 HTTP 请求(底层是 TCP)
  2. 判断请求是否是静态资源还是动态资源
  3. 如果是静态资源怎么处理
  4. 如果是动态资源怎么处理
  5. 关闭 Web 服务器
  1. """
  2. #!/usr/bin/python3
  3. # coding:utf-8
  4. #
  5. # Copyright (C) 2024 - 2024 Jasonakeke, Inc. All Rights Reserved
  6. # @Desc :我们自己开发的 web 服务器
  7. # @Time : 2024/7/31 22:17
  8. # @Author : Code_By_Jasonakeke
  9. # @Email : 2284037977@qq.com
  10. # @File : my_web.py
  11. # @IDE : PyCharm
  12. """from socket import socket, AF_INET, SOCK_STREAM
  13. from threading import Thread
  14. from time import strftime, localtime
  15. from _socket import SOL_SOCKET, SO_REUSEADDR
  16. from MyFramework import handle_request
  17. # 开发自己的 web 服务器主类classMyWebHttpServer(object):def__init__(self, port):# 创建 HTTP 服务器的套接字
  18. server_socket = socket(AF_INET, SOCK_STREAM)# 设置端口号复用,出现退出之后,不需要等待几分钟,直接释放端口
  19. server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR,True)
  20. server_socket.bind(('', port))
  21. server_socket.listen(128)
  22. self.server_socket = server_socket
  23. # 处理请求的函数@staticmethoddefhande_browser_request(new_socket):# 接收客户端的请求
  24. recv_data = new_socket.recv(4096)# 如果没有收到数据,那么请求无效,关闭套接字,直接退出iflen(recv_data)==0:
  25. new_socket.close()return# 对接收的字节数据,转换成字符
  26. request_data = recv_data.decode('utf-8')print("浏览器请求的数据:", request_data)
  27. request_array = request_data.split(' ', maxsplit =2)# 得到请求路径
  28. request_path = request_array[1]print("请求路径是:", request_path)# 如果请求路径是 /,自动设置为 /index.htmlif request_path =='/':
  29. request_path ='/index.html'# 根据请求路径来判断是否是动态资源函数静态资源if request_path.endswith('.html'):''' 动态资源的请求 '''# 动态资源的处理交给 Web 框架来处理,需要把请求参数传给 Web 框架,可能会有多个参数,所以采用字典结果
  30. params ={'request_path': request_path
  31. }# Web 框架处理动态资源请求之后,返回一个响应
  32. response = handle_request(params)
  33. new_socket.send(response)
  34. new_socket.close()else:''' 静态资源的请求 '''# 响应主体页面
  35. response_body =None# 响应头
  36. response_header =None
  37. response_type ='text/html'# 响应头第一行
  38. response_first_line =None# 其实就是根据请求路径读取 /static/ 目录中静态的文件数据,响应给客户端try:# 读取 static 目录中的文件数据,rb 模式是一种兼容模式,可以打开图片,也可以打开 jswithopen('static'+ request_path,'rb')as f:
  39. response_body = f.read()if request_path.endswith('.jpg'):
  40. response_type ='image/wbep'
  41. response_first_line ='HTTP/1.1 200 OK\r\n'# 响应头
  42. response_header =('Content-Length: '+str(len(response_body))+'\r\n'+'Content-Type: '+ response_type +'; charset=iso-8859-1\r\n'+'Date: '+ strftime('%Y-%m-%d %H:%M:%S', localtime())+'\r\n'+'Server: keke\r\n')except Exception as e:# 浏览器想读取的文件可能不存在withopen('static/404.html','rb')as f:# 响应主体页面
  43. response_body = f.read()
  44. response_first_line ='HTTP/1.1 404 Not Found\r\n'# 响应头
  45. response_header =('Content-Length: '+str(len(response_body))+'\r\n'+'Content-Type: '+ response_type +'; charset=iso-8859-1\r\n'+'Date: '+ strftime('%Y-%m-%d %H:%M:%S', localtime())+'\r\n'+'Server: keke\r\n')finally:# 组成响应数据,发给客户端
  46. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  47. new_socket.send(response)# 关闭套接字
  48. new_socket.close()# 启动服务器 ,并且接收客户端的请求defstart(self):# 循环并且多线程来接收客户端的请求whileTrue:
  49. new_socket, ip_port = self.server_socket.accept()print("客户端的 ip 和端口是:", ip_port)# 一个客户端请求交给一个线程处理
  50. sub_thread = Thread(target = self.hande_browser_request, args =(new_socket,))# 设置守护线程
  51. sub_thread.daemon =True
  52. sub_thread.start()defmain():# 创建服务器对象
  53. web_server = MyWebHttpServer(8080)# 启动服务器
  54. web_server.start()if __name__ =='__main__':
  55. main()

开发Web框架程序

  1. 根据请求路径,动态响应对应的数据
  2. 如果请求路径,没有对应的响应数据也需要返回404页面
  1. """
  2. # coding:utf-8
  3. #
  4. # Copyright (C) 2024 - 2024 Jasonakeke, Inc. All Rights Reserved
  5. # @Desc :自定义 Web 框架
  6. # @Time : 2024/8/1 22:07
  7. # @Author : Code_By_Jasonakeke
  8. # @Email : 2284037977@qq.com
  9. # @File : MyFramework.py
  10. # @IDE : PyCharm
  11. """from time import strftime, localtime
  12. # 处理动态资源请求defhandle_request(params):
  13. request_path = params['request_path']# 当前的请求路径有与之对应的动态响应if request_path =='/index.html':
  14. response = index()return response
  15. else:# 没有动态资源的数据,返回 404页面return page_not_found()# 专门处理 index.html 的请求defindex():
  16. data = strftime('%Y-%m-%d %H:%M:%S', localtime())
  17. response_body = data
  18. response_first_line ='HTTP/1.1 200 OK\r\n'# 响应头
  19. response_header =('Content-Length: '+str(len(response_body))+'\r\n'+'Content-Type: text/html; charset=iso-8859-1\r\n'+'Date: '+ strftime('%Y-%m-%d %H:%M:%S', localtime())+'\r\n'+'Server: keke\r\n')
  20. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
  21. # 处理没有找到对应的动态资源defpage_not_found():# 浏览器想读取的文件可能不存在withopen('static/404.html','rb')as f:# 响应主体页面
  22. response_body = f.read()
  23. response_first_line ='HTTP/1.1 404 Not Found\r\n'# 响应头
  24. response_header =('Content-Length: '+str(len(response_body))+'\r\n'+'Content-Type: text/html; charset=iso-8859-1\r\n'+'Date: '+ strftime('%Y-%m-%d %H:%M:%S', localtime())+'\r\n'+'Server: keke\r\n')
  25. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  26. return response

使用模板来展示响应内容

  1. 自己设计一个模板,中有一些地方采用动态的数据替代
  2. 怎么替代,替代什么数据
  1. <!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="utf-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1"><title>首页 - 电影列表</title><linkhref="/css/bootstrap.min.css"rel="stylesheet"><scriptsrc="/js/jquery-1.12.4.min.js"></script><scriptsrc="/js/bootstrap.min.js"></script></head><body><divclass="navbar navbar-inverse navbar-static-top "><divclass="container"><divclass="navbar-header"><buttonclass="navbar-toggle"data-toggle="collapse"data-target="#mymenu"><spanclass="icon-bar"></span><spanclass="icon-bar"></span><spanclass="icon-bar"></span></button><ahref="#"class="navbar-brand">电影列表</a></div><divclass="collapse navbar-collapse"id="mymenu"><ulclass="nav navbar-nav"><liclass="active"><ahref="">电影信息</a></li><li><ahref="">个人中心</a></li></ul></div></div></div><divclass="container"><divclass="container-fluid"><tableclass="table table-hover"><tr><th>序号</th><th>名称</th><th>导演</th><th>上映时间</th><th>票房</th><th>电影时长</th><th>类型</th><th>备注</th><th>删除电影</th></tr>
  2. {%datas%}
  3. </table></div></div></body></html>

开发框架的路由列表功能

  1. 以后开发新的动作资源的功能只需要增加一个条件判断分支和一个专门处理的函数
  2. 路由:就是请求的 URL 路径和处理函数直接的映射
  3. 路由表 请求路径****处理函数/index.htmlindex/userinfo.htmluser_info

注意:用户的动态资源请求通过遍历路由表找到对应的处理函数来完成的

  1. """
  2. #!/usr/bin/python3
  3. # coding:utf-8
  4. #
  5. # Copyright (C) 2024 - 2024 Jasonakeke, Inc. All Rights Reserved
  6. # @Desc :自定义 Web 框架
  7. # @Time : 2024/8/1 22:07
  8. # @Author : Code_By_Jasonakeke
  9. # @Email : 2284037977@qq.com
  10. # @File : MyFramework.py
  11. # @IDE : PyCharm
  12. """from time import strftime, localtime
  13. # 处理动态资源请求defhandle_request(params):
  14. request_path = params['request_path']for path, func in route_list:if request_path == path:return func()else:return page_not_found()# 当前的请求路径有与之对应的动态响应# if request_path == '/index.html':# response = index()# return response# elif request_path == '/userinfo.html':# response = user_info()# return response# else:# return page_not_found()# 专门处理 index.html 的请求defindex():
  15. response_body =None
  16. date = strftime('%Y-%m-%d %H:%M:%S', localtime())# response_body = datawithopen('template/index.html','r', encoding ='utf-8')as f:
  17. response_body = f.read()
  18. response_body = response_body.replace('{%datas%}', date)
  19. response_first_line ='HTTP/1.1 200 OK\r\n'# 响应头
  20. response_header ='Server: keke\r\n'
  21. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
  22. # 处理没有找到对应的动态资源defpage_not_found():# 浏览器想读取的文件可能不存在withopen('static/404.html','rb')as f:# 响应主体页面
  23. response_body = f.read()
  24. response_first_line ='HTTP/1.1 404 Not Found\r\n'# 响应头
  25. response_header ='Server: keke\r\n'
  26. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  27. return response
  28. defuser_info():
  29. response_body =None
  30. date = strftime('%Y-%m-%d %H:%M:%S', localtime())# response_body = datawithopen('template/user_info.html','r', encoding ='utf-8')as f:
  31. response_body = f.read()
  32. response_body = response_body.replace('{%datas%}', date)
  33. response_first_line ='HTTP/1.1 200 OK\r\n'# 响应头
  34. response_header ='Server: keke\r\n'
  35. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
  36. # 定义路由表
  37. route_list ={('/index.html', index),('/userinfo.html', user_info),}

采用装饰器的方式添加路由

  1. 采用带参数的装饰器
  2. 在任何一个处理函数的基础上增加一个添加路由的功能
  1. """
  2. #!/usr/bin/python3
  3. # coding:utf-8
  4. #
  5. # Copyright (C) 2024 - 2024 Jasonakeke, Inc. All Rights Reserved
  6. # @Desc :自定义 Web 框架
  7. # @Time : 2024/8/1 22:07
  8. # @Author : Code_By_Jasonakeke
  9. # @Email : 2284037977@qq.com
  10. # @File : MyFramework.py
  11. # @IDE : PyCharm
  12. """from functools import wraps
  13. from time import strftime, localtime
  14. # 定义路由表
  15. route_list =[]# route_list = {# ('/index.html', index),# ('/userinfo.html', user_info),# }# 调用一个带参数的装饰器defroute(request_path):"""
  16. :param request_path: URL 请求
  17. :return:
  18. """defadd_route(func):# 添加路由到路由表
  19. route_list.append((request_path, func))@wraps(func)definvoke(*arg,**kwargs):# 调用指定的处理函数并返回return func(*arg,**kwargs)return invoke
  20. return add_route
  21. # 处理动态资源请求defhandle_request(params):
  22. request_path = params['request_path']for path, func in route_list:if request_path == path:return func()else:return page_not_found()# 当前的请求路径有与之对应的动态响应# if request_path == '/index.html':# response = index()# return response# elif request_path == '/userinfo.html':# response = user_info()# return response# else:# return page_not_found()# 专门处理 index.html 的请求@route('/index.html')defindex():
  23. response_body =None
  24. date = strftime('%Y-%m-%d %H:%M:%S', localtime())# response_body = datawithopen('template/index.html','r', encoding ='utf-8')as f:
  25. response_body = f.read()
  26. response_body = response_body.replace('{%datas%}', date)
  27. response_first_line ='HTTP/1.1 200 OK\r\n'# 响应头
  28. response_header ='Server: keke\r\n'
  29. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
  30. # 处理没有找到对应的动态资源defpage_not_found():# 浏览器想读取的文件可能不存在withopen('static/404.html','rb')as f:# 响应主体页面
  31. response_body = f.read()
  32. response_first_line ='HTTP/1.1 404 Not Found\r\n'# 响应头
  33. response_header ='Server: keke\r\n'
  34. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  35. return response
  36. @route('/userinfo.html')defuser_info():
  37. response_body =None
  38. date = strftime('%Y-%m-%d %H:%M:%S', localtime())# response_body = datawithopen('template/user_info.html','r', encoding ='utf-8')as f:
  39. response_body = f.read()
  40. response_body = response_body.replace('{%datas%}', date)
  41. response_first_line ='HTTP/1.1 200 OK\r\n'# 响应头
  42. response_header ='Server: keke\r\n'
  43. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response

小结:使用带参数的装饰器,可以把路由自动的添加到路由列表中

电影列表页面的开发案例

  1. 查询数据
  2. 根据查询的数据得到动态的内容
  1. """
  2. #!/usr/bin/python3
  3. # coding:utf-8
  4. #
  5. # Copyright (C) 2024 - 2024 Jasonakeke, Inc. All Rights Reserved
  6. # @Desc :自定义 Web 框架
  7. # @Time : 2024/8/1 22:07
  8. # @Author : Code_By_Jasonakeke
  9. # @Email : 2284037977@qq.com
  10. # @File : MyFramework.py
  11. # @IDE : PyCharm
  12. """from functools import wraps
  13. from time import strftime, localtime
  14. from pymysql import connect
  15. # 定义路由表
  16. route_list =[]# route_list = {# ('/index.html', index),# ('/userinfo.html', user_info),# }# 调用一个带参数的装饰器defroute(request_path):"""
  17. :param request_path: URL 请求
  18. :return:
  19. """defadd_route(func):# 添加路由到路由表
  20. route_list.append((request_path, func))@wraps(func)definvoke(*arg,**kwargs):# 调用指定的处理函数并返回return func(*arg,**kwargs)return invoke
  21. return add_route
  22. # 处理动态资源请求defhandle_request(params):
  23. request_path = params['request_path']for path, func in route_list:if request_path == path:return func()else:return page_not_found()# 当前的请求路径有与之对应的动态响应# if request_path == '/index.html':# response = index()# return response# elif request_path == '/userinfo.html':# response = user_info()# return response# else:# return page_not_found()# 专门处理 index.html 的请求@route('/index.html')defindex():
  24. response_body =None# date = strftime('%Y-%m-%d %H:%M:%S', localtime())# response_body = data# 1.从 MySQL 中查询数据
  25. conn = connect(host ='127.0.0.1', port =3306, user ='root', password ='123456', database ='test', charset ='utf8')
  26. cursor = conn.cursor()
  27. cursor.execute('select * from t_movies')
  28. result = cursor.fetchall()print(result)
  29. datas =''for row in result:
  30. datas +='''
  31. <tr>
  32. <td>%s</td>
  33. <td>%s</td>
  34. <td>%s</td>
  35. <td>%s</td>
  36. <td>%s元</td>
  37. <td>%s</td>
  38. <td>%s</td>
  39. <td>%s</td>
  40. <td> <input type='button' value='删除'/></td>
  41. </tr>
  42. '''% row
  43. print(datas)withopen('template/index.html','r', encoding ='utf-8')as f:
  44. response_body = f.read()
  45. response_body = response_body.replace('{%datas%}', datas)
  46. response_first_line ='HTTP/1.1 200 OK\r\n'# 响应头
  47. response_header ='Server: keke\r\n'
  48. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
  49. # 处理没有找到对应的动态资源defpage_not_found():# 浏览器想读取的文件可能不存在withopen('static/404.html','rb')as f:# 响应主体页面
  50. response_body = f.read()
  51. response_first_line ='HTTP/1.1 404 Not Found\r\n'# 响应头
  52. response_header ='Server: keke\r\n'
  53. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  54. return response
  55. @route('/userinfo.html')defuser_info():
  56. response_body =None
  57. date = strftime('%Y-%m-%d %H:%M:%S', localtime())# response_body = datawithopen('template/user_info.html','r', encoding ='utf-8')as f:
  58. response_body = f.read()
  59. response_body = response_body.replace('{%datas%}', date)
  60. response_first_line ='HTTP/1.1 200 OK\r\n'# 响应头
  61. response_header ='Server: keke\r\n'
  62. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
标签: python 开发语言

本文转载自: https://blog.csdn.net/weixin_43344151/article/details/140833504
版权归原作者 Jasonakeke 所有, 如有侵权,请联系我们删除。

“开发自己的 Web 框架”的评论:

还没有评论