一、web框架概述
web框架 :为web服务器提供服务的应用程序,专门负责处理用户的动态资源请求
WSGI协议 :web服务器和web框架之间进行协同工作的一个规则,规定web服务器把动态资源的请求信息传给web框架处理,web框架把处理好的结果返回给web服务器
工作流程
web服务器接收浏览器发起的请求,如果是动态资源请求找web框架来处理
web框架负责处理浏览器的动态资源请求,把处理的结果发生给web服务器
web服务器再把响应结果发生给浏览器
二、框架程序开发 1. web服务器-动态资源判断
根据请求资源路径的后缀名进行判断,如果请求资源路径的后缀名是.html,则是动态资源请求,让web框架程序进行处理。否则是静态资源请求,让web服务器程序进行处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 import socketimport threadingimport sysimport frameworkclass HttpWebServer (object ): def __init__ (self, port ): 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(("192.168.0.101" , port)) tcp_server_socket.listen(128 ) self.tcp_server_socket = tcp_server_socket @staticmethod def handle_client_request (new_socket ): recv_client_data = new_socket.recv(4096 ) if len (recv_client_data) == 0 : print ('关闭浏览器了' ) 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 ] if request_path == '/' : request_path = '/index.html' if request_path.endswith('.html' ): '''动态资源请求''' env = { "request_path" :request_path } status,headers,response_body = framework.handle_request(env) 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 : '''静态资源请求''' try : with open ("static" + request_path, "rb" ) as file: file_data = file.read() except Exception as e: response_line = 'HTTP/1.1 404 Not Found\r\n' response_header = 'Server:PWS1.0\r\n' with open ('static/error.html' , 'rb' ) as file: file_data = file.read() response_body = file_data response_data = (response_line + response_header + "\r\n" ).encode("utf-8" ) + response_body new_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 new_socket.send(response_data) finally : new_socket.close() def start (self ): while True : new_socket, ip_port = self.tcp_server_socket.accept() sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,), daemon=True ) sub_thread.start() def main (): port = 9000 web_server = HttpWebServer(port) web_server.start() if __name__ == '__main__' : main()
2. web框架开发
接收web服务器的动态资源请求,处理请求并把处理结果返回给web服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 '''web 框架的职责:专门负责处理动态资源请求''' import timedef index (): status = '200 OK' response_header = [('Server' ,'PWS2.0' )] data = time.ctime() return status, response_header,data def not_found (): 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' ] print ('接收到的动态资源请求:' ,request_path) if request_path == '/index.html' : result = index() return result else : result = not_found() return result
3. 模版替换功能开发
把web框架-模板文件中的模板变量{%content%}
替换为请求时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def index (): status = "200 OK" ; response_header = [("Server" , "PWS2.0" )] with open ("template/index.html" , "r" ) as file: file_data = file.read() data = time.ctime() result = file_data.replace('{%content%}' ,data) return status, response_header, result
4. 路由列表功能开发
路由:请求的URL到处理函数的映射,也就是说提前关联处理请求的URL和处理函数
(1)使用一个路由列表进行管理,通过路由列表保存每一个路由
请求路径
处理函数
/login.html
login函数
/index.html
index函数
/center.html
center函数
1 2 3 4 5 route_list = [ ("/index.html" , index), ("/center.html" , center) ]
(2)根据用户请求遍历路由列表,处理用户请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 '''web 框架的职责:专门负责处理动态资源请求''' import timedef index (): status = "200 OK" ; response_header = [("Server" , "PWS2.0" )] with open ("template/index.html" , "r" ) as file: file_data = file.read() data = time.ctime() result = file_data.replace('{%content%}' ,data) return status, response_header, result def center (): status = "200 OK" ; response_header = [("Server" , "PWS2.0" )] with open ("template/center.html" , "r" ) as file: file_data = file.read() data = time.ctime() result = file_data.replace('{%content%}' ,data) return status, response_header, result def not_found (): 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' ] print ('接收到的动态资源请求:' ,request_path) for path,func in route_list: if request_path == path: result = func() return result result = not_found() return result
5. 装饰器方式添加路由
优点:完成路由的自动添加
装饰器类型:带参数的装饰器(需要接收一个url参数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 '''web 框架的职责:专门负责处理动态资源请求''' import timeroute_list = [] def route (path ): def decorator (func ): route_list.append((path,func)) def inner (): return func return inner return decorator @route('/index.html' ) def index (): status = "200 OK" ; response_header = [("Server" , "PWS2.0" )] with open ("template/index.html" , "r" ) as file: file_data = file.read() data = time.ctime() result = file_data.replace('{%content%}' ,data) return status, response_header, result @route('/center.html' ) def center (): status = "200 OK" ; response_header = [("Server" , "PWS2.0" )] with open ("template/center.html" , "r" ) as file: file_data = file.read() data = time.ctime() result = file_data.replace('{%content%}' ,data) return status, response_header, result def not_found (): 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' ] print ('接收到的动态资源请求:' ,request_path) for path,func in route_list: if request_path == path: result = func() return result result = not_found() return result
6. 显示信息页面的开发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 '''web 框架的职责:专门负责处理动态资源请求''' import timeimport pymysqlroute_list = [] def route (path ): def decorator (func ): route_list.append((path,func)) def inner (): return func return inner return decorator @route('/index.html' ) def index (): status = "200 OK" ; response_header = [("Server" , "PWS2.0" )] with open ("template/index.html" , "r" ) as file: file_data = file.read() conn = pymysql.connect(host='192.168.241.128' , port=3306 , user='root' , password='123456' , database='test' , charset='utf8' ) cursor = conn.cursor() sql = 'select * from info;' cursor.execute(sql) result = cursor.fetchall() print (result) cursor.close() conn.close() data = "" for row in result: data += '''<tr> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td> <td><input type = 'button' value = '添加' id = 'toadd' systemidvaule = '00007'></td> </tr>''' % row result = file_data.replace('{%content%}' ,data) return status, response_header, result @route('/center.html' ) def center (): status = "200 OK" ; response_header = [("Server" , "PWS2.0" )] with open ("template/center.html" , "r" ) as file: file_data = file.read() data = time.ctime() result = file_data.replace('{%content%}' ,data) return status, response_header, result def not_found (): 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' ] print ('接收到的动态资源请求:' ,request_path) for path,func in route_list: if request_path == path: result = func() return result result = not_found() return result
7. 数据接口的开发
web框架程序还可以开发数据接口,为客户端程序提供数据服务
步骤
根据sql语句查询数据库
把数据转成json字符串返回
浏览器通过指定接口地址获取web框架提供的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 @route('/center_data.html' ) def center_data (): status = "200 OK" ; response_header = [("Server" , "PWS2.0" ), ("Content-Type" ,"text/html;charset=utf-8" )] conn = pymysql.connect(host='192.168.241.128' , port=3306 , user='root' , password='123456' , database='test' , charset='utf8' ) cursor = conn.cursor() sql = '''select i.code, i.short, i.chg, i.turnover, i.price, i.highs, f.note_info from info as i inner join focus as f on i.id = f.info_id;''' cursor.execute(sql) result = cursor.fetchall() cursor.close() conn.close() center_data_list = [] for row in result: ccenter_dict = dict () ccenter_dict["code" ] = row[0 ] ccenter_dict["short" ] = row[1 ] ccenter_dict["chg" ] = row[2 ] ccenter_dict["turnover" ] = row[3 ] ccenter_dict["price" ] = str (row[4 ]) ccenter_dict["highs" ] = str (row[5 ]) ccenter_dict["node_info" ] = row[6 ] center_data_list.append(ccenter_dict) json_str = json.dumps(center_data_list,ensure_ascii=False ) print (json_str) return status, response_header, json_str
8. 使用ajax请求数据渲染页面
在个人中心模板文件添加ajax请求获取个人中心数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 $(document ).ready (function ( ){ $.get ("center_data.html" ,function (data ) { var $table = $(".table" ); for (var i = 0 ; i < data.length ; i++){ var oCenterData = data[i]; var oTr = '<tr>' + '<td>' + oCenterData.code +'</td>' + '<td>' + oCenterData.short +'</td>' + '<td>' + oCenterData.chg +'</td>' + '<td>' + oCenterData.turnover +'</td>' + '<td>' + oCenterData.price +'</td>' + '<td>' + oCenterData.highs +'</td>' + '<td>' + oCenterData.note_info +'</td>' + '<td><a type="button" class="btn btn-default btn-xs" href="/update/000007.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a></td>' + '<td><input type="button" value="删除" id="toDel" name="toDel" systemidvaule="000007"></td>' + '</tr>' $table.append (oTr) } }, "json" );
9. logging日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import logginglogging.basicConfig(level=logging.DEBUG, format ='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s' , filename="log.txt" , filemode="w" ) logging.debug('这是一个debug级别的日志信息' ) logging.info('这是一个info级别的日志信息' ) logging.warning('这是一个warning级别的日志信息' ) logging.error('这是一个error级别的日志信息' ) logging.critical('这是一个critical级别的日志信息' )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import socketimport threadingimport sysimport frameworkimport logginglogging.basicConfig(level=logging.DEBUG, format ='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s' , filename="log.txt" , filemode="w" ) if request_path.endswith(".html" ): """这里是动态资源请求,把请求信息交给框架处理""" logging.info("动态资源请求:" + request_path) ... else : """这里是静态资源请求""" logging.info("静态资源请求:" + request_path) ... if len (sys.argv) != 2 : print ("执行命令如下: python3 xxx.py 9000" ) logging.warning("用户在命令行启动程序参数个数不正确!" ) return if not sys.argv[1 ].isdigit(): print ("执行命令如下: python3 xxx.py 9000" ) logging.warning("用户在命令行启动程序参数不是数字字符串!" ) return def handle_request (env ): request_path = env["request_path" ] print ("接收到的动态资源请求:" , request_path) for path, func in route_list: if request_path == path: result = func() return result else : logging.error("没有设置相应的路由:" + request_path) result = not_found() return result