10 分离式web框架
10 分离式web框架
wsgiref模块:
将http请求封装成以键值对的形式封装成字典environ:
"PATH_INFO"对应的值为请求文件路径,
“QUERY_STRING”对应的值为get请求发送的数据
“REQUEST+METHOD”对应的值为请求方式。
同时封装一个发送响应格式的函数start_server;通过特定的方式return [ ]返回数据并调用内置方法返回给浏览器。
GET和POST请求:
请求参数的获取:
GET请求参数的传递在url请求文件路径后边拼接显式传输,可以直接在wsgiref模块封装好的environ请求信息字典中以键“QUERY_STRING”取值获取传递的参数;
POST请求参数的传递是在请求信息的请求数据部分,
通过在wsgiref模块封装好的environ请求信息字典中以键“CONTENT_LENGTH”获取参数(bytes类型)长度,然后通过environ["wsgi.input"].read(长度)获取传递的参数(bytes类型)
请求参数的处理:
内置模块(from urllib.parse import parse_qs)
执行parse_qs()进行格式化成字典找到对应的参数值(列表形式,注意get为字符串,post为字节);
具体处理方式:
GET:
query_string=environ["QUERY_STRING"] |
#'QUERY_STRING': 'username=zhangsan&userpsd=abc', |
query_string=parse_qs(query_string) |
#{ 'username':['zhangsan'],'userpsd':['abc']} |
name=query_request["username"][0] |
'zhangsan' |
psd=query_request["userpsd"][0] |
'abc' |
POST:
leng=int(environ.get('CONTENT_LENGTH',0)) |
#'CONTENT_LENGTH'参数长度 |
query_string=environ['wsgi.input'].read(leng) |
#{ 'username':['zhangsan'],'userpsd':['abc']} |
query_string=parse_qs(query_string) |
#{ b'username':[b'zhangsan'],b'userpsd':[b'abc']} |
name=query_string[b'username'][0].decode("utf-8") |
'zhangsan' |
psd=query_string[b'userpsd'][0].decode("utf-8") |
'abc' |
wsgiref封装的请求信息:
GET |
{……. 'SERVER_PORT': '8888', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/auth', 'QUERY_STRING': 'username=zhangsan&userpsd=abc', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8888', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'wsgi.input': <_io.BufferedReader name=916>…….} |
POST |
{…… 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8888', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '29', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'REQUEST_METHOD': 'POST', 'PATH_INFO': '/auth', 'QUERY_STRING': '', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'wsgi.input': <_io.BufferedReader name=880>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>} |
客户端浏览器访问:
在浏览器地址栏直接输入地址端口:127.0.0.1:8888
服务器server端python程序(分离版本):
manege.py:
1 from wsgiref.simple_server import make_server #python内置基于socket的服务程序模块 2 from urls import func_mappers #自己封装的请求文件路径与对应操作映射模块 3 4 def application(environ,start_reponse): 5 """ 6 基于wsgiref模块实现客户端请求数据的封装(字典environ)和封装的响应格式发送函数(statr_response)进行服务响应 7 :param environ: wsgiref模块封装好的请求信息字典 8 :param start_reponse: wsgiref模块封装的响应格式发送函数 9 :return: 10 """ 11 path=environ["PATH_INFO"] #通过字典取值获取请求路径信息 12 start_reponse("200 Ok",[("Content","text/html")]) #分装好的函数发送响应格式信息 13 # print(path) 14 # 根据请求文件路径,映射与之对应的函数操作 15 for mapper in func_mappers: 16 if path==mapper[0]: 17 data=mapper[1](environ) 18 else: 19 data=b"Sorry:404 not find" 20 return [data] 21 22 if __name__ == '__main__': 23 httpd=make_server("127.0.0.1",8888,application) 24 httpd.serve_forever()
modles.py
1 # 连接数据库,创建需要实用的信息表 2 import pymysql 3 conn=pymysql.connect("127.0.0.1","root","","web") 4 cursor=conn.cursor() 5 6 user=[("zhangsan","abc"), 7 ("lisi","123")] 8 sql_createTable="create table userinfo(uid int primary key auto_increment,name char(12) unique not null ,password char(32) not null )" 9 sql_insret="insert into userinfo(name,password) values" 10 11 cursor.execute(sql_createTable) 12 13 for data in user: 14 sql_value=sql_insret+str(data) 15 cursor.execute(sql_value) 16 conn.commit() 17 18 cursor.close() 19 conn.close()
urls.py
1 # 路由信息:请求文件路径与对应操作函数的映射表 2 from views import * 3 func_mappers=[ 4 ("/",func_login), 5 ("/auth",func_auth)]
views.py
1 from urllib.parse import parse_qs #内置模块方法用于处理请求传递的数据格式 2 from webauth import auth 3 4 # 客户端请求根目录时响应登录页面 5 def func_login(environ): 6 with open("login.html", "rb")as f: 7 data = f.read() 8 return data 9 10 # 客户端提交登录时,判断请求方式,获取提交的数据,进行验证 11 def func_auth(environ): 12 13 if environ.get("REQUEST_METHOD") == "GET": 14 query_request = environ["QUERY_STRING"] 15 # print(user) 16 # print(environ) 17 18 query_request = parse_qs(query_request) 19 print(repr(query_request)) 20 username = query_request["username"][0] 21 psd = query_request["userpsd"][0] 22 23 elif environ.get("REQUEST_METHOD") == "POST": 24 # 获取请求体数据的长度,因为提交过来的数据需要用它来提取,注意POST请求和GET请求的获取数据的方式不同 25 try: 26 request_body_size = int(environ.get('CONTENT_LENGTH', 0)) 27 except (ValueError): 28 request_body_size = 0 29 # POST请求获取数据的方式 30 request_data = environ['wsgi.input'].read(request_body_size) 31 print('>>>>>', request_data) # >>>>> b'username=chao&password=123',是个bytes类型数据 32 print('?????', environ['QUERY_STRING']) # ????? 空的,因为post请求只能按照上面这种方式取数据 33 # parse_qs可以帮我们解析数据 34 re_data = parse_qs(request_data) 35 print('拆解后的数据', re_data) # 拆解后的数据 {b'password': [b'123'], b'username': [b'chao']} 36 username=re_data[b'username'][0].decode("utf-8") 37 psd=re_data[b'userpsd'][0].decode("utf-8") 38 39 # 获取用户名和密码之后进行提交验证 40 status = auth(username, psd) 41 if status: 42 with open("login_success.html", "rb")as f: 43 data = f.read() 44 else: 45 data = "<h1> login error</h1>".encode("utf-8") 46 return data
webauth.py
1 # 登录认证使用:连接数据库查询用户名和密码进行检验 2 def auth(username,psd): 3 import pymysql 4 conn = pymysql.connect("127.0.0.1", "root", "", "web") 5 cursor = conn.cursor() 6 sql_select=f"select * from userinfo where name='{username}' and password='{psd}' " 7 # print(sql_select) 8 ret=cursor.execute(sql_select) #函数返回结果ret为匹配到的记录条数 9 cursor.close() 10 conn.cursor() 11 return ret 12 # print(auth('zhangsan','abc'))
login.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <link rel="icon" href="faviron.ico"> 6 <title>登录</title> 7 </head> 8 <body> 9 <div> 10 11 <form action="auth" method="post" name="login"><!--以post请求方式auth验证--> 12 13 <!--<form action="auth" method="get" name="login"><!–以get请求方式auth验证–>--> 14 <table> 15 <tr> 16 <td><label for="username">用户名</label></td> 17 <td><input type="text" name="username" id="username"></td> 18 </tr> 19 <tr> 20 <td> <label for="userpsd">密码</label></td> 21 <td><input type="password" name="userpsd" id="userpsd"></td> 22 </tr> 23 <tr> 24 <td ><input type="reset"></td> 25 <td ><input type="submit"></td> 26 </tr> 27 </table> 28 29 </form> 30 </div> 31 </body> 32 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> 33 <script> 34 $(function () { 35 //在登录之前在客户端进行账号、密码初级判断 36 $("form[name='login']").submit (function () { 37 var name = $("#username").val(); 38 var psd = $("#userpsd").val(); 39 40 if (name == "" || psd == "") { 41 alert("用户名和密码不能为空!"); 42 return false 43 } 44 }) 45 }) 46 </script> 47 </html>
login_success.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="refresh" content=""> 6 <meta name="keywords" content=""> 7 <style></style> 8 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> 9 <link rel="stylesheet" href=""> 10 <title>首页</title> 11 </head> 12 <body> 13 <div> 14 <h1>登录成功!</h1> 15 </div> 16 </body> 17 </html>