web框架介绍
2.wsgiref模块
最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。而wsgiref模块就是python基于wsgi协议开发的服务模块。
示例学习
from wsgiref.simple_server import make_server
"""make_server已经封装了socket,所以不需要额外调用!"""
# import socket
import socket # 重用端口需要
"""
wsgiref 按着FTTP请求协议解析数据
按着HTTP相应协议封装数据
我们就可以专注于web业务开发
python下的web服务器接口协议:WSGI(Web Server Gateway Interface)
wsgiref是为python实现WSGI的一个模块!
"""
def application(environ, start_response):
"""自定义的回调函数 两个形参接受的参数为
按着http协议解析的数据字典:environ(存着所有的请求数据,包括头和体,键值对的方式!)
按着http协议组装数据的函数:stare_response
"""
# print(environ)
# print(type(environ))
"""start_response函数进行响应组装,包括响应首行(状态码等,首行必须有),响应头(可无)(可以忽略里面的\r\n这些格式)"""
start_response('200 OK', [('Content-Type', 'text/html')])
"""在这里我遇到一个编码出错的问题,原因是我用的win10系统,主机名用的是汉语,
win默认的编码方式是gbk。在这里十分感谢老男孩路飞学城的alex和刘耀导师帮我指导并解决了这个问题"""
# 得到当前的请求路径
path = environ.get('PATH_INFO')
print("当前的路径:" ,path)
if path == "/login":
with open('login.html', 'r', encoding='utf-8') as f:
data = f.read()
elif path == '/index':
with open('index.html', 'r', encoding='utf-8') as f:
data = f.read()
else:
data = '<h1>--404 Not find!--</h1>'
"""WSGI要求的返回值必须为一个数组"""
return [data.encode('utf8')]
if __name__ == "__main__":
"""封装了socket"""
httped = make_server("", 8088, application)
"""重用端口,(这里是我自己领悟的!老师没有讲)"""
httped.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
"""等待用户连接 conn,addr=socket.accept()"""
httped.serve_forever()
简化版
from wsgiref.simple_server import make_server
import socket # 重用端口需要
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
path = environ.get('PATH_INFO')
if path == "/login":
with open('login.html', 'r', encoding='utf-8') as f:
data = f.read()
else:
data = '<h1>--404 Not find!--</h1>'
return [data.encode('utf8')]
if __name__ == "__main__":
httped = make_server("", 8088, application)
httped.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
httped.serve_forever()
3.自己DIV一个web框架
简单版
from wsgiref.simple_server import make_server
import socket # 重用端口需要
# 方案二:
def login(environ):
with open('../login.html', 'rb') as f:
data = f.read()
return data
def index(environ):
with open('../index.html', 'rb') as f:
data = f.read()
return data
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
path = environ.get('PATH_INFO')
read_dic = {
'/login':login,
'/index':index,
}
try:
return [read_dic[path](environ)]
except:
return [b'404']
if __name__ == "__main__":
httped = make_server("", 8088, application)
httped.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
httped.serve_forever()
html文件代码
略!
加入数据库版
目录结构
main.py
from wsgiref.simple_server import make_server
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html'),("Charset","utf8")])
path = environ.get("PATH_INFO")
print("PATH",environ.get("PATH_INFO"))
from urls import url_patterns
func=None
for item in url_patterns:
if path==item[0]:
func=item[1]
break
if func:
return [func(environ)]
else:
return [b'404!']
httpd = make_server('', 9988, application)
# 开始监听HTTP请求:
httpd.serve_forever()
urls.py
from views import *
url_patterns=[
("/login",login), #视图函数
("/reg",reg),
("/index",index),
("/favicon.ico",fav),
("/timer",timer),
("/auth",auth),
]
views.py
def login(environ):
with open("templates/login.html","rb") as f:
data=f.read()
return data
from urllib.parse import parse_qs
def index(environ):
with open("templates/index.html","rb") as f:
data=f.read()
return data
def fav(environ):
with open("templates/favicon.ico","rb") as f:
data=f.read()
return data
def reg(environ):
with open("templates/reg.html","rb") as f:
data=f.read()
return data
def timer(environ):
import datetime
now = datetime.datetime.now().strftime('%y-%m-%d %X')
return now.encode("utf8")
def auth(request):
# 取出用户名和密码的逻辑
try:
request_body_size = int(request.get('CONTENT_LENGTH', 0)) #如果没有对应的字典值就返回0
except (ValueError):
request_body_size = 0
request_body = request['wsgi.input'].read(request_body_size)
data = parse_qs(request_body)
user=data.get(b"user")[0].decode("utf8")
pwd=data.get(b"pwd")[0].decode("utf8")
#连接数据库
import pymysql
conn = pymysql.connect(host='127.0.0.1',port= 3306,user = 'root',passwd='abc123',db='web_yuan') # db:库名
#创建游标
cur = conn.cursor()
SQL="select * from userinfo WHERE NAME ='%s' AND PASSWORD ='%s'"%(user,pwd)
cur.execute(SQL)
if cur.fetchone():
f=open("templates/backend.html","rb")
data=f.read()
data=data.decode("utf8")
return data.encode("utf8")
else:
return b"user or pwd is wrong"
models.py ---单独执行,用于生成数据
# 生成用户表
"""准备数据库
create database web_yuan;
"""
import pymysql
conn = pymysql.connect(host='127.0.0.1',port=3306,user = 'root',passwd='abc123',db='web_yuan')
cur = conn.cursor()
sql = '''
create table userinfo(
id int primary key,
name varchar(32),
password varchar(32)
)
'''
cur.execute(sql)
conn.commit()
cur.close()
conn.close()
"""数据库中操作
insert userinfo values(1,'yuan','123');
"""
html代码
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h4>welcome to luffyCity!</h4>
</body>
</html>
reg.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h4>注册页面</h4>
</body>
</html>
backend.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>Index</h3>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h4>登录页面</h4>
<form action="http://127.0.0.1:9988/auth" method="post">
用户名<input type="text" name="user">
密码<input type="password" name="pwd">
<input type="submit">
</form>
</body>
</html>
总结
- 0.main.py:启动文件,封装了socket
- 1.urls.py:路径与视图函数的映射关系 ---url控制器
- 2.views.py:视图函数部分,固定有一个形参-environ(包含所有的请求数据)---视图函数
- 3.timplates文件夹:存放html文件 ---模板
- 4.models:在项目启动前,在数据库中创建表结构 ----与数据库相关