0


Python开发自定义Web框架

在这里插入图片描述

文章目录

开发自定义Web框架

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

如果请求资源路径的后缀名是

  1. .html

则是动态资源请求, 让web框架程序进行处理。
否则是静态资源请求,让web服务器程序进行处理。

1.开发Web服务器主体程序

1、接受客户端HTTP请求(底层是TCP)

  1. # -*- coding: utf-8 -*-# @File : My_Web_Server.py# @author: Flyme awei # @email : 1071505897@qq.com# @Time : 2022/7/24 21:28from socket import*import threading
  2. # 开发自己的Web服务器主类classMyHttpWebServer(object):def__init__(self, port):# 创建 HTTP服务的 TCP套接字
  3. server_socket = socket(AF_INET, SOCK_STREAM)# 设置端口号互用,程序退出之后不需要等待,直接释放端口
  4. server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR,True)# 绑定 ip port
  5. server_socket.bind(('', port))# listen使套接字变为了被动连接
  6. server_socket.listen(128)
  7. self.server_socket = server_socket
  8. # 处理请求函数
  9. @staticmethod# 静态方法defhandle_browser_request(new_socket):# 接受客户端发来的数据
  10. recv_data = new_socket.recv(4096)# 如果没有数据,那么请求无效,关闭套接字,直接退出iflen(recv_data)==0:
  11. new_socket.close()return# 启动服务器,并接受客户端请求defstart(self):# 循环并多线程来接收客户端请求whileTrue:# accept等待客户端连接
  12. new_socket, ip_port = self.server_socket.accept()print("客户端ip和端口", ip_port)# 一个客户端的请求交给一个线程来处理
  13. sub_thread = threading.Thread(target=MyHttpWebServer.handle_browser_request, args=(new_socket,))# 设置当前线程为守护线程
  14. sub_thread.setDaemon(True)
  15. sub_thread.start()# 启动子线程# Web 服务器程序的入口defmain():
  16. web_server = MyHttpWebServer(8080)
  17. web_server.start()if __name__ =='__main__':
  18. main()

2、判断请求是否是静态资源还是动态资源

  1. # 对接收的字节数据进行转换为字符数据
  2. request_data = recv_data.decode('utf-8')print("浏览器请求的数据:", request_data)
  3. request_array = request_data.split(' ', maxsplit=2)# 得到请求路径
  4. request_path = request_array[1]print("请求的路径是:", request_path)if request_path =="/":# 如果请求路径为根目录,自动设置为:/index.html
  5. request_path ="/index.html"# 判断是否为:.html 结尾if request_path.endswith(".html"):"动态资源请求"passelse:"静态资源请求"pass

3、如果静态资源怎么处理?
在这里插入图片描述

  1. "静态资源请求"# 根据请求路径读取/static 目录中的文件数据,相应给客户端
  2. response_body =None# 响应主体
  3. response_header =None# 响应头的第一行
  4. response_first_line =None# 响应头内容
  5. response_type ='test/html'# 默认响应类型try:# 读取 static目录中相对应的文件数据,rb模式是一种兼容模式,可以打开图片,也可以打开jswithopen('static'+request_path,'rb')as f:
  6. response_body = f.read()if request_path.endswith('.jpg'):
  7. response_type ='image/webp'
  8. response_first_line ='HTTP/1.1 200 OK'
  9. response_header ='Content-Length:'+str(len(response_body))+'\r\n'+ \
  10. 'Content-Type: '+ response_type +'; charset=utf-8\r\n'+ \
  11. 'Date:'+ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+'\r\n'+ \
  12. 'Server: Flyme awei Server\r\n'# 浏览器读取的文件可能不存在except Exception as e:withopen('static/404.html','rb')as f:
  13. response_body = f.read()# 响应的主体页面内容# 响应头
  14. response_first_line ='HTTP/1.1 404 Not Found\r\n'
  15. response_header ='Content-Length:'+str(len(response_body))+'\r\n'+ \
  16. 'Content-Type: text/html; charset=utf-8\r\n'+ \
  17. 'Date:'+ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+'\r\n'+ \
  18. 'Server: Flyme awei Server\r\n'# 最后都会执行的代码finally:# 组成响应数据发送给(客户端)浏览器
  19. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  20. new_socket.send(response)# 关闭套接字
  21. new_socket.close()

在这里插入图片描述
静态资源请求验证:
在这里插入图片描述

4、如果动态资源又怎么处理

  1. if request_path.endswith(".html"):"动态资源请求"# 动态资源的处理交给Web框架来处理,需要把请求参数交给Web框架,可能会有多个参数,采用字典结构
  2. params ={'request_path': request_path
  3. }# Web框架处理动态资源请求后,返回一个响应
  4. response = MyFramework.handle_request(params)
  5. new_socket.send(response)
  6. new_socket.close()

5、关闭Web服务器

  1. new_socket.close()

Web服务器主体框架总代码展示:

  1. # -*- coding: utf-8 -*-# @File : My_Web_Server.py# @author: Flyme awei # @email : 1071505897@qq.com# @Time : 2022/7/24 21:28import sys
  2. import time
  3. from socket import*import threading
  4. import MyFramework
  5. # 开发自己的Web服务器主类classMyHttpWebServer(object):def__init__(self, port):# 创建 HTTP服务的 TCP套接字
  6. server_socket = socket(AF_INET, SOCK_STREAM)# 设置端口号互用,程序退出之后不需要等待,直接释放端口
  7. server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR,True)# 绑定 ip port
  8. server_socket.bind(('', port))# listen使套接字变为了被动连接
  9. server_socket.listen(128)
  10. self.server_socket = server_socket
  11. # 处理请求函数
  12. @staticmethod# 静态方法defhandle_browser_request(new_socket):# 接受客户端发来的数据
  13. recv_data = new_socket.recv(4096)# 如果没有数据,那么请求无效,关闭套接字,直接退出iflen(recv_data)==0:
  14. new_socket.close()return# 对接收的字节数据进行转换为字符数据
  15. request_data = recv_data.decode('utf-8')print("浏览器请求的数据:", request_data)
  16. request_array = request_data.split(' ', maxsplit=2)# 得到请求路径
  17. request_path = request_array[1]print("请求的路径是:", request_path)if request_path =="/":# 如果请求路径为根目录,自动设置为:/index.html
  18. request_path ="/index.html"# 判断是否为:.html 结尾if request_path.endswith(".html"):"动态资源请求"# 动态资源的处理交给Web框架来处理,需要把请求参数交给Web框架,可能会有多个参数,采用字典结构
  19. params ={'request_path': request_path
  20. }# Web框架处理动态资源请求后,返回一个响应
  21. response = MyFramework.handle_request(params)
  22. new_socket.send(response)
  23. new_socket.close()else:"静态资源请求"# 根据请求路径读取/static 目录中的文件数据,相应给客户端
  24. response_body =None# 响应主体
  25. response_header =None# 响应头的第一行
  26. response_first_line =None# 响应头内容
  27. response_type ='test/html'# 默认响应类型try:# 读取 static目录中相对应的文件数据,rb模式是一种兼容模式,可以打开图片,也可以打开jswithopen('static'+request_path,'rb')as f:
  28. response_body = f.read()if request_path.endswith('.jpg'):
  29. response_type ='image/webp'
  30. response_first_line ='HTTP/1.1 200 OK'
  31. response_header ='Content-Length:'+str(len(response_body))+'\r\n'+ \
  32. 'Content-Type: '+ response_type +'; charset=utf-8\r\n'+ \
  33. 'Date:'+ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+'\r\n'+ \
  34. 'Server: Flyme awei Server\r\n'# 浏览器读取的文件可能不存在except Exception as e:withopen('static/404.html','rb')as f:
  35. response_body = f.read()# 响应的主体页面内容# 响应头
  36. response_first_line ='HTTP/1.1 404 Not Found\r\n'
  37. response_header ='Content-Length:'+str(len(response_body))+'\r\n'+ \
  38. 'Content-Type: text/html; charset=utf-8\r\n'+ \
  39. 'Date:'+ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+'\r\n'+ \
  40. 'Server: Flyme awei Server\r\n'# 最后都会执行的代码finally:# 组成响应数据发送给(客户端)浏览器
  41. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  42. new_socket.send(response)# 关闭套接字
  43. new_socket.close()# 启动服务器,并接受客户端请求defstart(self):# 循环并多线程来接收客户端请求whileTrue:# accept等待客户端连接
  44. new_socket, ip_port = self.server_socket.accept()print("客户端ip和端口", ip_port)# 一个客户端的请求交给一个线程来处理
  45. sub_thread = threading.Thread(target=MyHttpWebServer.handle_browser_request, args=(new_socket,))# 设置当前线程为守护线程
  46. sub_thread.setDaemon(True)
  47. sub_thread.start()# 启动子线程# Web 服务器程序的入口defmain():
  48. web_server = MyHttpWebServer(8080)
  49. web_server.start()if __name__ =='__main__':
  50. main()

2.开发Web框架主体程序

1、根据请求路径,动态的响应对应的数据

  1. # -*- coding: utf-8 -*-# @File : MyFramework.py# @author: Flyme awei # @email : 1071505897@qq.com# @Time : 2022/7/25 14:05import time
  2. # 自定义Web框架# 处理动态资源请求的函数defhandle_request(parm):
  3. request_path = parm['request_path']if request_path =='/index.html':# 当前请求路径有与之对应的动态响应,当前框架只开发了 index.html的功能
  4. response = index()return response
  5. else:# 没有动态资源的数据,返回404页面return page_not_found()# 当前 index函数,专门处理index.html的请求defindex():# 需求,在页面中动态显示当前系统时间
  6. data = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
  7. response_body = data
  8. response_first_line ='HTTP/1.1 200 OK\r\n'
  9. response_header ='Content-Length:'+str(len(response_body))+'\r\n'+ \
  10. 'Content-Type: text/html; charset=utf-8\r\n'+ \
  11. 'Date:'+ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+'\r\n'+ \
  12. 'Server: Flyme awei Server\r\n'
  13. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
  14. defpage_not_found():withopen('static/404.html','rb')as f:
  15. response_body = f.read()# 响应的主体页面内容# 响应头
  16. response_first_line ='HTTP/1.1 404 Not Found\r\n'
  17. response_header ='Content-Length:'+str(len(response_body))+'\r\n'+ \
  18. 'Content-Type: text/html; charset=utf-8\r\n'+ \
  19. 'Date:'+ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+'\r\n'+ \
  20. 'Server: Flyme awei Server\r\n'
  21. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  22. return response

2、如果请求路径,没有对应的响应数据也需要返回404页面
在这里插入图片描述

3.使用模板来展示响应内容

1、自己设计一个模板

  1. index.html

,中有一些地方采用动态的数据来替代

  1. <!DOCTYPE html><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>

2、怎么替代,替代什么数据

  1. response_body = response_body.replace('{%datas%}', data)

在这里插入图片描述

4.开发框架的路由列表功能

1、以后开发新的动作资源的功能,只需要:
a、增加一个条件判断分支
b、增加一个专门处理的函数

2、路由: 就是请求的URL路径和处理函数直接的映射。

3、路由表
请求路径处理函数/index.htmlindex函数/user_info.htmluser_info函数

  1. # 定义路由表
  2. route_list ={('/index.html', index),('/user_info.html', user_info)}for path, func in route_list:if request_path == path:return func()else:# 没有动态资源的数据,返回404页面return page_not_found()

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

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

1、采用带参数的装饰器

  1. # -*- coding: utf-8 -*-# @File : My_Web_Server.py# @author: Flyme awei # @email : 1071505897@qq.com# @Time : 2022/7/24 21:28# 定义路由表
  2. route_list =[]# route_list = {# ('/index.html', index),# ('/user_info.html', user_info)# }# 定义一个带参数的装饰器defroute(request_path):# 参数就是URL请求defadd_route(func):# 添加路由表
  3. route_list.append((request_path, func))
  4. @wraps(func)definvoke(*args,**kwargs):# 调用指定的处理函数,并返回结果return func()return invoke
  5. return add_route
  6. # 处理动态资源请求的函数defhandle_request(parm):
  7. request_path = parm['request_path']# if request_path == '/index.html': # 当前请求路径有与之对应的动态响应,当前框架只开发了 index.html的功能# response = index()# return response# elif request_path == '/user_info.html': # 个人中心的功能# return user_info()# else:# # 没有动态资源的数据,返回404页面# return page_not_found()for path, func in route_list:if request_path == path:return func()else:# 没有动态资源的数据,返回404页面return page_not_found()

2、在任何一个处理函数的基础上增加一个添加路由的功能

  1. @route('/user_info.html')

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

6.电影列表页面的开发案例

在这里插入图片描述

1、查询数据

  1. my_web.py
  1. # -*- coding: utf-8 -*-# @File : My_Web_Server.py# @author: Flyme awei # @email : 1071505897@qq.com# @Time : 2022/7/24 21:28import socket
  2. import sys
  3. import threading
  4. import time
  5. import MyFramework
  6. # 开发自己的Web服务器主类classMyHttpWebServer(object):def__init__(self, port):# 创建HTTP服务器的套接字
  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. # 处理浏览器请求的函数
  13. @staticmethoddefhandle_browser_request(new_socket):# 接受客户端发送过来的数据
  14. recv_data = new_socket.recv(4096)# 如果没有收到数据,那么请求无效,关闭套接字,直接退出iflen(recv_data)==0:
  15. new_socket.close()return# 对接受的字节数据,转换成字符
  16. request_data = recv_data.decode('utf-8')print("浏览器请求的数据:", request_data)
  17. request_array = request_data.split(' ', maxsplit=2)# 得到请求路径
  18. request_path = request_array[1]print('请求路径是:', request_path)if request_path =='/':# 如果请求路径为跟目录,自动设置为/index.html
  19. request_path ='/index.html'# 根据请求路径来判断是否是动态资源还是静态资源if request_path.endswith('.html'):'''动态资源的请求'''# 动态资源的处理交给Web框架来处理,需要把请求参数传给Web框架,可能会有多个参数,所有采用字典机构
  20. params ={'request_path': request_path,}# Web框架处理动态资源请求之后,返回一个响应
  21. response = MyFramework.handle_request(params)
  22. new_socket.send(response)
  23. new_socket.close()else:'''静态资源的请求'''
  24. response_body =None# 响应主体
  25. response_header =None# 响应头
  26. response_first_line =None# 响应头的第一行# 其实就是:根据请求路径读取/static目录中静态的文件数据,响应给客户端try:# 读取static目录中对应的文件数据,rb模式:是一种兼容模式,可以打开图片,也可以打开jswithopen('static'+ request_path,'rb')as f:
  27. response_body = f.read()if request_path.endswith('.jpg'):
  28. response_type ='image/webp'
  29. response_first_line ='HTTP/1.1 200 OK'
  30. response_header ='Server: Laoxiao_Server\r\n'except Exception as e:# 浏览器想读取的文件可能不存在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: Laoxiao_Server\r\n'finally:# 组成响应数据,发送给客户端(浏览器)
  34. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  35. new_socket.send(response)
  36. new_socket.close()# 关闭套接字# 启动服务器,并且接受客户端的请求defstart(self):# 循环并且多线程来接受客户端的请求whileTrue:
  37. new_socket, ip_port = self.server_socket.accept()print("客户端的ip和端口", ip_port)# 一个客户端请求交给一个线程来处理
  38. sub_thread = threading.Thread(target=MyHttpWebServer.handle_browser_request, args=(new_socket,))
  39. sub_thread.setDaemon(True)# 设置当前线程为守护线程
  40. sub_thread.start()# 子线程要启动# web服务器程序的入口defmain():
  41. web_server = MyHttpWebServer(8080)
  42. web_server.start()if __name__ =='__main__':
  43. main()
  1. MyFramework.py
  1. # -*- coding: utf-8 -*-# @File : My_Web_Server.py# @author: Flyme awei # @email : 1071505897@qq.com# @Time : 2022/7/24 21:28import time
  2. from functools import wraps
  3. import pymysql
  4. # 定义路由表
  5. route_list =[]# route_list = {# # ('/index.html',index),# # ('/userinfo.html',user_info)# }# 定义一个带参数装饰器defroute(request_path):# 参数就是URL请求defadd_route(func):# 添加路由到路由表
  6. route_list.append((request_path, func))
  7. @wraps(func)definvoke(*arg,**kwargs):# 调用我们指定的处理函数,并且返回结果return func()return invoke
  8. return add_route
  9. # 处理动态资源请求的函数defhandle_request(params):
  10. request_path = params['request_path']for path, func in route_list:if request_path == path:return func()else:# 没有动态资源的数据,返回404页面return page_not_found()# if request_path =='/index.html': # 当前的请求路径有与之对应的动态响应,当前框架,我只开发了index.html的功能# response = index()# return response## elif request_path =='/userinfo.html': # 个人中心的功能,user_info.html# return user_info()# else:# # 没有动态资源的数据,返回404页面# return page_not_found()# 当前user_info函数,专门处理userinfo.html的动态请求
  11. @route('/userinfo.html')defuser_info():# 需求:在页面中动态显示当前系统时间
  12. date = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())# response_body =datawithopen('template/user_info.html','r', encoding='utf-8')as f:
  13. response_body = f.read()
  14. response_body = response_body.replace('{%datas%}', date)
  15. response_first_line ='HTTP/1.1 200 OK\r\n'
  16. response_header ='Server: Laoxiao_Server\r\n'
  17. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
  18. # 当前index函数,专门处理index.html的请求
  19. @route('/index.html')defindex():# 需求:从数据库中取得所有的电影数据,并且动态展示# date = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())# response_body =data# 1、从MySQL中查询数据
  20. conn = pymysql.connect(host='localhost', port=3306, user='root', password='******', database='test', charset='utf8')
  21. cursor = conn.cursor()
  22. cursor.execute('select * from t_movies')
  23. result = cursor.fetchall()# print(result)
  24. datas =""for row in result:
  25. datas +='''<tr>
  26. <td>%s</td>
  27. <td>%s</td>
  28. <td>%s</td>
  29. <td>%s</td>
  30. <td>%s 亿人民币</td>
  31. <td>%s</td>
  32. <td>%s</td>
  33. <td>%s</td>
  34. <td> <input type='button' value='删除'/> </td>
  35. </tr>
  36. '''% row
  37. print(datas)# 把查询的数据,转换成动态内容withopen('template/index.html','r', encoding='utf-8')as f:
  38. response_body = f.read()
  39. response_body = response_body.replace('{%datas%}', datas)
  40. response_first_line ='HTTP/1.1 200 OK\r\n'
  41. response_header ='Server: Laoxiao_Server\r\n'
  42. response =(response_first_line + response_header +'\r\n'+ response_body).encode('utf-8')return response
  43. # 处理没有找到对应的动态资源defpage_not_found():withopen('static/404.html','rb')as f:
  44. response_body = f.read()# 响应的主体页面内容(字节)# 响应头 (字符数据)
  45. response_first_line ='HTTP/1.1 404 Not Found\r\n'
  46. response_header ='Server: Laoxiao_Server\r\n'
  47. response =(response_first_line + response_header +'\r\n').encode('utf-8')+ response_body
  48. return response

2、根据查询的数据得到动态的内容
在这里插入图片描述

标签: python 服务器 后端

本文转载自: https://blog.csdn.net/m0_68744965/article/details/125964322
版权归原作者 北极的三哈 所有, 如有侵权,请联系我们删除。

“Python开发自定义Web框架”的评论:

还没有评论