【一】Web框架本质
将前端、数据库整合到一起的基于互联网传输的python代码
web框架也可以简单的理解为是软件开发架构里面的'服务端'
1.服务端
import socket
server=socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
sock,addr=server.accept()
data=sock.recv(1024)
sock.send(b"xxxx")
2.客户端
import socket
client=socket.socket()
client.connect(('127.0.0.1',8080))
while True:
client.send(b'ssss')
data=client.recv(1024)
3.http协议
1.四大特性
1.无状态
2.应用层协议
3.服务器只能响应客服端请求,客服端发起请求
4.短链接
5.持久连接
2.数据格式
(1)请求格式
客户端给服务端发送消息应该遵循的数据格式
请求首行(请求方法 请求路径 协议版本)
请求头(一大堆k:v键值对)
(换行不能省略)
请求体(携带敏感数据:密码 身份照号...) 不是一直都有
(2) 响应格式
服务端给客户端发送消息应该遵循的数据格式
响应首行(响应状态码 协议版本)
响应头(一大堆k:v键值对)
(换行不能省略)
响应体(给浏览器展示给用户看的页面内容)
3.响应状态码
| 状态码类型 | 描述
| 1xx | 告诉客户端,本次请求,服务端还在持续处理中,并**没有结束**。
| 2xx | 告诉客户端,本次请求,服务端已经接收并**成功受理**了。
| 3xx | 告诉客户端,服务端位置发生改变,希望客户端**重定向**访问跳转新的服务器地址进行请求
| 4xx | 告诉**客户端**,本次**请求有误**,服务器无法处理。
| 5xx | 告诉客户端,本次请求服务端在处理过程中**服务端出错**了。
4.基于不同的后缀响应不同的内容
服务端
import socket
server = socket.socket()
server.bind(('127.0.0.1', 8082))
server.listen(5)
while True:
sock, addr = server.accept()
data = sock.recv(1024)
# 将请求相关数据先转成字符串
data_str = data.decode('utf8') # 'GET /login HTTP/1.1\r\nHost: 127.0.0.1:8081\r\n......'
sock.send(b'HTTP1.1 200 OK\r\n\r\n')
# 然后去字符串中截取出我们需要的内容(按照空格切割字符串 获取第二个元素即可)
current_path = data_str.split(' ')[1]
# 根据后缀的不同返回不同的内容
if current_path == '/login':
sock.send(b'hello login!!!')
elif current_path == '/register':
sock.send(b'hello register')
else:
sock.send(b'404 error')
【二】基于wsgiref模块搭建web框架
# 1.利用模块搭建服务端
# 2.利用模块处理好的HTTP字典数据编写业务
查找用户url后缀对象的键值对数据
from wsgiref import simple_server
def run(request, response):
"""
:param request: 请求相关的数据
:param response: 响应相关的数据
:return: 返回给客户端的展示数据
"""
# print(request) # 字典类型的数据(模块自动处理HTTP请求数据 便于后续数据获取)
response('200 OK', []) # 固定编写 无需掌握
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 __name__ == '__main__':
server = simple_server.make_server('127.0.0.1', 8080, run)
'''一致监听本机8080端口 一旦有请求访问 自动触发run方法的执行'''
server.serve_forever()
1.优化
(1)问题
如果网站很多,必须人为的添加elif
每个分支下的功能根据业务逻辑的不同可能会比较复杂的逻辑
(2)函数优化
● 将匹配和功能封装成 元组和函数
● 但是还是会存在问题
○ 所有的代码全部放在一个py文件过于冗余
○ 不便于后期管理维护
(3)模块优化
根据功能的不同拆分成不同的py文件
urls.py 对应关系的存储
views.py 业务逻辑的编写
● 以后要想新增功能 只需要在urls.py中添加对应关系 view.py中编写函数
● 但还是会存在新的问题
○ 业务函数的代码中 可能会频繁的使用到不同的html页面
为了避免文件类型的混乱 单独开设一个文件夹存储所有的html文件
templates文件夹 存储项目所需的html文件
(5)静态优化
html所学的css、js、第三方框架代码都是写完之后很少做改动的文件
所以可以统一存放在某个文件夹下
static文件夹 存储项目所需的'静态文件'(后续再讲)
优化实现
from wsgiref import simple_server
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):
# run函数体中添加下列代码
current_path = request.get("PATH_INFO")
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')]
if __name__ == '__main__':
'''服务端监听的IP和端口'''
IP = '127.0.0.1'
PORT = 8080
'''创建一个服务端对象'''
server = simple_server.make_server(IP, PORT, run)
'''监听本机8080端口 一旦有请求访问 自动触发run方法的执行'''
server.serve_forever()
# 模块封装了socket代码并将请求数据处理成诸多k:v键值对
优化版本分层
[1]views.py
● --存储路由与函数对应关系(写相应函数的)
# 功能函数
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()
[2]urls.py
● --存储函数--》映射到view层的函数
from views import *
# 后缀匹配
urls = (
('/register', register),
('/login', login),
('/index', index),
)
[3]server.py
● --存储启动及分配代码---》启动的
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()
2.模板文件与静态文件
[1]templates文件夹
--存储html文件
[2]static文件夹
--存储html页面所需静态资源(后续详细讲解或自行百度)
【三】动静态网页
静态网页
页面上的数据是直接写死的 万年不变
eg:编写的 html
动态网页
页面上的数据是通过代码动态获取的 实时可变
eg:
1.页面上展示当前时间(后端获取传递给前端界面)
2.页面上展示数据库数据(后端链接数据库查询数据再传递给页面)
● 静态网页适合用于内容较少且不需要频繁更新的场景,如关于我们、联系我们等基础介绍页面。
● 动态网页则更适用于需要实时交互、内容丰富且需要定期更新的场景,如新闻资讯、在线购物平台等,通过服务器端的动态处理,提供了更好的用户体验和更高的业务复杂性处理能力。
【四】Jinja2模板语法
1.案例--》页面展示当前时间
后端
def get_time(request):
# 1.获取当前时间
import time
c_time = time.strftime('%Y-%m-%d %X')
# 2.读取html文件
with open(r'templates/get_time.html','r',encoding='utf8') as f:
data = f.read()
# 3.思考:如何给字符串添加一些额外的字符串数据>>>:字符串替换
new_data = data.replace('random_str',c_time)
return new_data
前端
<h1>展示后端获取的时间数据</h1>
<span>random_str</span>
2.jinja2模板语法--》写上述案例
1.views.py--》写功能函数的
from jinja2 import Template
def get_dict(request):
user_dict = {'name': 'dream', 'pwd': 123, 'hobby': 'read'}
new_list = [11, 22, 33, 44, 55, 66]
with open(r'templates/get_dict.html', 'r', encoding='utf8') as f:
data = f.read()
temp_obj = Template(data)
res = temp_obj.render({'user':user_dict,'new_list':new_list})
return res
2.templates---》写html的
<h1>字典数据展示</h1>
<p>{{ user }}</p>
<p>{{ user.name }}</p>
<p>{{ user['pwd'] }}</p>
<p>{{ user.get('hobby') }}</p>
<h1>列表数据展示</h1>
<p>
{% for i in new_list%}
<span>元素:{{ i }}</span>
{% endfor %}
</p>
【五】关键字
1.urls.py
● 后缀与函数名对应关系
○ ('/index',register)
○ 后缀专业名词称之为'路由'
○ 函数名专业名词称之为'视图函数'
○ urls.py专业名词称之为'路由层'
2.views.py
● 专门编写业务逻辑代码
○ 可以是函数 也可以是类
○ 函数专业名词称之为'视图函数'
○ 类专业名词称之为'视图类'
○ views.py专业名词称之为'视图层'
3.templates文件夹
● 专门存储html文件
● html文件专业名词称之为'模板文件'
● templates文件夹专业名词称之为'模板层'
4.static文件夹
● 专门存储静态文件资源
○ 页面所需css文件、js文件、图片文件、第三方文件可统称为'静态资源'
【六】python主流web框架
### 【1】Django框架
- Django框架比较完整并且大
- 大而全
- 笨重
### 【2】flask框架
- 小而精
- 依赖于第三方模块
### 【3】Tornado框架
- 速度比较快
- 游戏服务器上
### 【4】fastapi框架
- 支持异步,比较快
- 内置了很多高级的功能
【七】网络框架和MVC架构
1.网络架构
网络架构其实就是人家帮我们封装好底层源码调用后的框架
2.MVC架构
# Model - View - Controller
# 模型 - 视图 - 控制器
(1)模型(Model)
# 用于封装与应用程序的业务逻辑相关的数据及对数据的处理方法,是Web应用程序中用于处理应用程序的数据逻辑的部分,Model只提供功能性的接口,通过这些接口可以获取Model的所有功能。
# Model不依赖于View和Controller,它们可以在任何时候调用Model访问数据。
# 有些Model还提供了事件通知机制,为在其上注册过的View或Controller提供实时的数据更新。
# (2)视图(View)
# 负责数据的显示和呈现,View是对用户的直接输出。
# MVC中的一个Model通常为多个View提供服务。
# 为了获取Model的实时更新数据,View应该尽早地注册到Model中。
#(3)控制器(Controller)
# 负责从用户端收集用户的输入,可以看成提供View的反向功能。
# 当用户的输入导致View发生变化时,这种变化必须是通过Model反映给View的。
# 在MVC架构下,Controller一般不能与View直接通信,这样提高了业务数据的一致性,即以Model作为数据中心。