Web框架本质
- web框架本质上就是一个socket服务端,但是它的功能非常强大
- 用户的浏览器可以看作一个拥有可视化界面的socket客户端
- 两者通过网络请求完成数据交互
手撸Web框架
【1】原始版本
- web框架可以是自己写的一个简陋的socket服务端
import socket
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
conn, addr = server.accept()
data = conn.recv(1024)
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 这里要符合http响应体
res = data.decode('utf-8').split(' ')[1]
if res == '/index':
conn.send(b'index oao')
elif res == '/login':
conn.send(b'login oao')
else:
conn.send(b'hello web')
conn.close()
1.socket代码过于重复
2.针对http请求数据没有完善的处理方式,自己处理起来很麻烦
【2】基于wsgiref模块搭建web框架
模块封装功能
from wsgiref import simple_server
def run(request, response):
"""
:param request: 请求相关的数据
:param response: 响应相关的数据
:return: 返回给客户端的展示数据
"""
response('200 OK', []) # 固定编写 无需掌握
return [b'hello jason']
if __name__ == '__main__':
server = simple_server.make_server('127.0.0.1', 8080, run)
'''监听本机8080端口 一旦有请求访问 自动触发run方法的执行'''
server.serve_forever()
# 模块封装了socket代码并将请求数据处理成诸多k:v键值对
路由对应响应
# run函数体中添加下列代码
current_path = request.get("PATH_INFO")
if current_path == '/login':
return [b'hello login html']
elif current_path == '/register':
return [b'hello register html']
return [b'404 error']
路由拆分流程
# 当有很多路由和响应的情况下不可能无限制编写if判断语句,应该设置对应关系并动态调用
def register(request):
return 'register'
def login(request):
return 'login'
def error(request):
with open(r'templates/error.html', 'r', encoding='utf8') as f:
return f.read()
urls = (
('/login',login),
('/register',register)
)
def run(request, response):
func_name = None
for url_tuple in urls:
if current_path == url_tuple[0]:
# 先获取对应的函数名
func_name = url_tuple[1]
# 一旦匹配上了 后续的对应关系就无需在循环比对了
break
# for循环运行完毕之后 func_name也有可能是None
if func_name:
res = func_name(request)
else:
res = error(request) # 顺手将request也传给函数 便于后续数据的获取
return [res.encode('utf8')]
【3】根据功能的不同拆分成不同的文件
# 功能函数
def register(request):
return 'register'
def login(request):
return 'login'
def index(request):
return 'index'
def error(request):
with open(r'templates/error.html', 'r', encoding='utf8') as f:
return f.read()
# 后缀匹配
urls = (
('/register', register),
('/login', login),
('/index', index),
)
from wsgiref import simple_server
from urls import urls
from views import error
def run(request, response):
response('200 OK', [])
current_path = request.get("PATH_INFO")
func_name = None
for url_tuple in urls: # ('/register', register)
if current_path == url_tuple[0]:
func_name = url_tuple[1]
break
if func_name:
res = func_name(request)
else:
res = error(request)
return [res.encode('utf8')]
if __name__ == '__main__':
server = simple_server.make_server('127.0.0.1', 8080, run)
server.serve_forever()
总结
- 拆分后好处在于要想新增一个功能,只需要在views.py中编写函数,urls.py添加对应关系即可
JinJa2模板语法
【1】模块安装
- JinJa2是第三方模块,需要pip install JinJa2
- 它支持将数据传输到html页面,并且提供类似于后端语言的语法,可以简单快速的处理数据
【2】动态展示当前时间
from jinja2 import Template
def get_time(env):
with open('templates/show_time.html', 'r', encoding='utf8') as fp:
data = fp.read()
now_time = time.strftime('%Y-%m-%d %H:%M:%S')
tmp = Template(data)
res = tmp.render(now_time=now_time)
return res
from views import *
urls = [
('/time',get_time)
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{now_time}}</h1>
</body>
</html>
主要关键字
urls.py
后缀与函数名对应关系
('/index',register)
后缀专业名词称之为'路由'
函数名专业名词称之为'视图函数'
urls.py专业名词称之为'路由层'
views.py
专门编写业务逻辑代码
可以是函数 也可以是类
函数专业名词称之为'视图函数'
类专业名词称之为'视图类'
views.py专业名词称之为'视图层'
templates文件夹
专门存储html文件
html文件专业名词称之为'模板文件'
templates文件夹专业名词称之为'模板层'
static文件夹
专门存储静态文件资源
页面所需css文件、js文件、图片文件、第三方文件可统称为'静态资源'