【一】web框架
- web框架本质上可以看成是一个功能强大的socket服务端,用户的浏览器可以看成是拥有可视化界面的socket客户端。
- 两者通过网络请求实现数据交互,从架构层面上先简单的将Web框架看做是对前端、数据库的全方位整合
【二】手撸web框架
【1】原始版本
(1)服务端
# [一] 导入模块
import socket
# [二]定义通信ip和端口
IP = '127.0.0.1'
PORT = 8082
# [三] 创建socket对象
server = socket.socket()
# [四] 监听端口
server.bind((IP, PORT))
# [五] 创建半连接池
server.listen(5)
while True:
# [六] 接收客户端链接和地址
sock,addr = server.accept()
# [七] 接收数据
data = sock.recv(1024)
print(f'这是来自客户端的信息:>>>>{data.decode("utf-8")}')
# [八] 回送数据
sock.send(b"hello client ")
(2)客户端
# [一] 导入模块
import socket
# [二]定义通信IP和端口
IP = '127.0.0.1'
PORT = 8082
# [三] 创建链接对象
client = socket.socket()
client.connect((IP, PORT))
while True:
# [四] 发送数据
client.send(b"hello server")
# [五]接收数据
data = client.recv(1024)
print(f"这是来服务端的数据:>>>>{data.decode('utf-8')}")
- 出现了一个问题
- 使用浏览器来充当客户端
- 服务端无法正常响应客户端(浏览器)的请求
浏览器和服务端进行交互是基于HTTP协议
【1】HTTP协议是什么
超文本传输协议:HTTP协议就是规范了浏览器和服务端之间进行数据交互和传输的标准
不仅仅能传输文字,还能传输图片/音频/视频/压缩包 ...
【2】HTTP协议的特点
(1)无状态
客户端向服务端发送请求,服务端正常响应数据。服务端不会保存客户端的任何信息
(2)基于TCP协议/IP协议之上的应用层协议
底层也是TCP协议
(3)无连接(短连接)
客户端向服务端发送连接请求,服务端正常响应。数据传输完成自动断开连接
(4)基于请求与响应模型
客户端向服务端发送连接请求,服务端才能正常响应客户端的请求
请求数据格式
请求方式 请求路径(地址)版本(Http1.0)
请求头
请求体
响应数据格式
请求方式 请求路径(地址) 状态码 版本(HTTP1.0)
响应头
响应体
1xx:客户端向服务端正常发送请求
2xx:服务端正常响应客户端数据
3xx:重定向
4xx:403:请求错误,404:访问资源不存在
5xx : 服务器宕机
- 优化
- 基于响应数据格式相应数据
【2】浏览器发送请求
- 遵循HTTP协议
- 四大特性
- 数据格式
- 响应状态码
# [一] 导入模块
import socket
# [二]定义通信ip和端口
IP = '127.0.0.1'
PORT = 8082
# [三] 创建socket对象
server = socket.socket()
# [四] 监听端口
server.bind((IP, PORT))
# [五] 创建半连接池
server.listen(5)
while True:
# [六] 接收客户端链接和地址
sock, addr = server.accept()
# [七] 接收数据
data = sock.recv(1024)
print(f'这是来自客户端的信息:>>>>{data.decode("utf-8")}')
# [八] 回送数据
# 服务端响应的数据需要符合HTTP响应格式
sock.send(b"HTTP1.1 200 OK\r\n\r\n hello client ")
- 弊端
- 根据访问地址访问到对应的资源
【3】路由对应响应
- 基于不同的后缀相应不同的内容
GET / HTTP/1.1
Host: 127.0.0.1:8082
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9
- 如何获取用户输入的url后缀
- HTTP请求数据
/favicon.ico
直接忽略 不影响判断
- 利用字符串切割和索引取值获取相应数据
# [一] 导入模块
import socket
from _socket import SO_REUSEADDR, SOL_SOCKET
# [二]定义通信ip和端口
IP = '127.0.0.1'
PORT = 8082
# [三] 创建socket对象
server = socket.socket()
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加
# [四] 监听端口
server.bind((IP, PORT))
# [五] 创建半连接池
server.listen(5)
while True:
# [六] 接收客户端链接和地址
sock, addr = server.accept()
# [七] 接收数据
data = sock.recv(1024)
# print(f'这是来自客户端的信息:>>>>{data.decode("utf-8")}')
# [八] 回送数据
# 服务端响应的数据需要符合HTTP响应格式
http_type = "HTTP1.1 200 OK\r\n\r\n"
# 将客户端请求相关数据先转成字符串
option = data.decode('utf8')
# 研究发现可以采用字符串切割获取路由
current_path = option.split(' ')[1]
print(current_path)
# 根据后缀的不同返回不同的内容
if current_path == '/login':
data = f'{http_type} hello zhangsan login!!!1'
sock.send(data.encode('utf-8'))
elif current_path == '/register':
data = f'{http_type} hello zhangsan register!!!!'
sock.send(data.encode('utf-8'))
else:
data = f'{http_type}404 zhangsan error'
sock.send(data.encode('utf-8'))
# 导入模块
import socket
from _socket import SO_REUSEADDR, SOL_SOCKET
# 创建服务端对象
server = socket.socket()
# 监听端口和IP
PORT = 8989
IP = "127.0.0.1"
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加
server.bind((IP, PORT))
# 创建半连接池
server.listen(5)
# 接收到客户端对象和客户端地址
while True:
conn, addr = server.accept()
# 从客户端接收到信息
data_from_client = conn.recv(1024)
data_from_client = data_from_client.decode("utf-8")
# 从上述请求数据中切分出指定的请求方式和请求路径
option = data_from_client.split(' ')
print(option)
# 请求方式
option_type = option[0]
# 请求路径
option_path = option[1]
# print(option_path)
http_res_type = "HTTP1.1 200 OK\r\n\r\n"
# 根据请求路径指定请求方法
if option_path == "/login":
res = f"{http_res_type} hello zhangsan login success"
conn.send(res.encode("utf-8"))
elif option_path == "/register":
res = f"{http_res_type} hello zhangsan register success"
conn.send(res.encode("utf-8"))
else:
res = f"{http_res_type} 404 not found"
conn.send(res.encode("utf-8"))
- 纯手撸框架缺陷:
- socket代码过于重复(每次搭建服务端都需要反复造轮子)
- 针对HTTP请求数据没有完善的处理方式(目前只能定向切割)
- 无法实现服务端的并发
【三】基于wsgiref模块搭建web框架
【1】模块封装功能
# [一] 导入模块
import socket
# [二]定义通信IP和端口
IP = '127.0.0.1'
PORT = 8082
# [三] 创建链接对象
client = socket.socket()
client.connect((IP, PORT))
while True:
# [四] 发送数据
client.send(b"hello server")
# [五]接收数据
data = client.recv(1024)
print(f"这是来服务端的数据:>>>>{data.decode('utf-8')}")
【2】路由对应响应
- 路由指的是HTTP请求的URL映射到响应的处理函数(或者视图函数)。
- 路由定义了不同URL请求应该由哪个程序中的哪个函数来处理,这种映射关系为路由规则
(1)wsgiref
1.0
from wsgiref import simple_server
def run(request, response):
"""
:param request: 请求相关的数据
:param response: 响应相关的数据
:return: 返回给客户端的展示数据
"""
response('200 OK', []) # 固定编写 无需掌握
return [b'hello zhangsan']
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键值对
(2)wsgiref
2.0
from wsgiref import simple_server
# 重写一个函数run函数
def run(request, response):
'''
:param request: 请求相关的数据
:param response: 响应相关的数据
:return:
'''
path = request.get("PATH_INFO")
response("200 OK",[]) # 固定的格式不需要更改
# 按照HTTP协议格式相应数据
# 创建response对象
if path == "/login":
return [b"zhangsan login"]
elif path == "/register":
return [b"zhangan register"]
else:
return [b"404 not found"]
if __name__ == '__main__':
# 指定服务器的IP和端口
IP = "127.0.0.1"
PORT = 8080
# 创建一个服务端对象
server = simple_server.make_server(IP, PORT, run)
# 启动服务端
server.serve_forever()
- 对request对象中的PATH_INFO属性提取实现了路由的筛选
- 还想再优化代码。不利于解耦合
(3)wsgiref
3.0
# 导入模块
import socket
from _socket import SO_REUSEADDR, SOL_SOCKET
# 创建服务端对象
server = socket.socket()
# 监听端口和IP
PORT = 8989
IP = "127.0.0.1"
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加
server.bind((IP, PORT))
# 创建半连接池
server.listen(5)
# 接收到客户端对象和客户端地址
while True:
conn, addr = server.accept()
# 从客户端接收到信息
data_from_client = conn.recv(1024)
data_from_client = data_from_client.decode("utf-8")
# 从上述请求数据中切分出指定的请求方式和请求路径
option = data_from_client.split(' ')
# 请求方式
option_type = option[0]
# 请求路径
option_path = option[1]
print(option_path)
http_res_type = "HTTP1.1 200 OK\r\n\r\n"
# 根据请求路径指定请求方法
if option_path == "/login":
res = f"{http_res_type} hello zhangsan login success"
conn.send(res.encode("utf-8"))
elif option_path == "/register":
res = f"{http_res_type} hello zhangsan register success"
conn.send(res.encode("utf-8"))
else:
res = f"{http_res_type} 404 not found"
conn.send(res.encode("utf-8"))
- 根据请求数据,切分出请求路径和请求方式,对不同的请求方式和路径进行不容的处理
- 每次都得必须重新写 socket 服务端
- 针对不同的请求路径,不同的if ~ else 函数
- 没有实现服务端的并发
(4)wsgiref
2.0
- 将每一个路由函数拆出去
- 新建一个路由和函数的映射关系
# 导入模块、
from wsgiref import simple_server
def login(request):
return "dream login"
def register(request):
return "dream register"
def error(request):
return "404 not found"
# 请求路径和请求函数的对应关系
urls = (
("/login", login),
("/register", register),
)
# 重写一个函数 run函数 :负责返回响应数据
def run(request, response):
'''
:param request: 请求相关的数据
:param response: 响应相关的数据
:return:
'''
# print(request)
# print("-----------------")
# print(f"response :>>> {response}")
path = request.get("PATH_INFO")
response("200 OK", []) # 固定的格式不需要更改
# 按照HTTP协议格式相应数据
# 创建response对象
# 路由地址和对应的函数左映射
func_name = None
for url in urls:
if path == url[0]:
func_name = url[1]
print(func_name)
break
if func_name:
response_data = func_name(request)
else:
response_data = error(request)
return [response_data.encode("utf-8")]
# 请求函数和请求地址之间的映射关系
def main():
# 指定服务器的IP和端口
IP = "127.0.0.1"
PORT = 8080
# 创建一个服务端对象
server = simple_server.make_server(IP, PORT, run)
# 启动服务端
server.serve_forever()
if __name__ == '__main__':
# print(type(back_url(path="/login")[0]))
main()
(5)wsgiref
3.0
- 将路由函数拆分成单个文件
views.py
:: 视图函数
def login(request):
return "dream login"
def register(request):
return "dream register"
def error(request):
return "404 not found"
def home(request):
return f"这是 home 页面"
- 将映射关系函数拆分成单个文件
urls.py
:: 路由视图
from views import login, register,error,home
# 请求路径和请求函数的对应关系
url_pattern = (
("/login", login),
("/register", register),
("/home", home),
)
- 主函数文件,负责调度和统一
# 导入模块、
from wsgiref import simple_server
from urls import url_pattern, error
# 重写一个函数 run函数 :负责返回响应数据
def run(request, response):
'''
:param request: 请求相关的数据
:param response: 响应相关的数据
:return:
'''
path = request.get("PATH_INFO")
response("200 OK", []) # 固定的格式不需要更改
func_name = None
for url in url_pattern:
if path == url[0]:
func_name = url[1]
print(func_name)
break
if func_name:
response_data = func_name(request)
else:
response_data = error(request)
return [response_data.encode("utf-8")]
def main():
# 指定服务器的IP和端口
IP = "127.0.0.1"
PORT = 8080
# 创建一个服务端对象
server = simple_server.make_server(IP, PORT, run)
# 启动服务端
server.serve_forever()
if __name__ == '__main__':
# print(type(back_url(path="/login")[0]))
main()
【三】模版文件和静态文件
【1】模版文件(templates)
- 存储前端页面的文件
- 登录注册页面
【2】静态文件(static)
- 负责存储静态的数据
- jQuery源码文件,bootstrap源码文件,本地头像或者音乐
【四】动态页面和静态页面
【1】静态页面
- 死页面:所有的数据都是固定不变的
- 404页面
- 内容固定:页面上的所有数据(文本、图片、链接等)都直接写入 HTML 文件,不会因为用户的不同请求或时间的变化而变化。
- 无需服务器处理:当用户访问静态网页时,浏览器直接从服务器下载对应的 HTML 文件并显示内容,服务器主要负责存储和分发已存在的网页资源。
- 加载速度快:由于内容不需服务器进一步处理,所以加载速度较快。
- 常见例子有:error.html、func.html等预定义的错误提示页面、功能说明页面等。
【2】动态页面
- 动态的渲染数据
- 内容实时更新:页面上的数据可以根据用户的请求、数据库查询结果或其他服务器端逻辑动态生成,这意味着同一页面可以呈现不同的内容给不同的用户或在不同时间访问的用户。
- 需要服务器处理:当用户访问 动态网页时,服务器会根据请求执行相应的脚本程序,调用后台数据库进行查询、计算等操作,然后再将处理后的数据返回给浏览器,浏览器负责渲染这些动态内容。
- 数据交互性强:动态网页支持与用户交互,如表单提交、搜索功能等,能更好地满足用户实时需求和个性化体验。
- 动态网页则更适用于需要实时交互、内容丰富且需要定期更新的场景,如新闻资讯、在线购物平台等,通过服务器端的动态处理,提供了更好的用户体验和更高的业务复杂性处理能力。
【五】jianjia2模版语法
【1】页面展示当前时间
(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
(2)前端
<h1>展示后端获取的时间数据</h1>
<span>random_str</span>
【2】jinja2模板语法
(1)下载安装
- 第三方模块需要先下载后使用
pip3 install jinja2
(2)功能
- 支持将数据传递到html页面并提供近似于后端的处理方式简单快捷的操作数据
(3)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
(4)templates
- --get_dict.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>
【六】网络框架和MVC架构
【1】网络框架
- 所谓网络框架是指这样的一组Python包,它能够使开发者专注于网站应用业务逻辑的开发,而无须处理网络应用底层的协议、线程、进程等方面。这样能大大提高开发者的工作效率,同时提高网络应用程序的质量。
- 在目前Python语言的几十个开发框架中,几乎所有的全栈网络框架都强制或引导开发者使用MVC架构开发Web应用。
- 所谓全栈网络框架,是指除了封装网络和线程操作,还提供HTTP栈、数据库读写管理、HTML模板引擎等一系列功能的网络框架。
- 本文重点讲解的Django、Tornado和Flask是全栈网络框架的典型标杆;而Twisted更专注于网络底层的高性能封装而不提供HTML模板引擎等界面功能,所以不能称之为全栈框架。
【2】MVC架构
- MVC(Model-View-Controller)模式最早由Trygve Reenskaug在1978年提出,在20世纪80年代是程序语言Smalltalk的一种内部架构。
- 后来MVC被其他语言所借鉴,成为了软件工程中的一种软件架构模式。
- MVC把Web应用系统分为3个基本部分。
(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作为数据中心。
【3】MVC架构图
- 这3个基本部分互相分离,使得在改进和升级界面及用户交互流程时,不需要重写业务逻辑及数据访问代码。MVC架构如图1所示。
注意:MVC在除Python外的其他语言中也有广泛应用,例如VC++的MFC、Java的Structs及Spring、C#的.NET开发框架,读者应该有深刻的体会。
【七】Python主流后端框架介绍
【1】Django
(1)介绍
- 相对于Python的其他Web框架,Django的功能是最完整的,Django定义了服务发布、路由映射、模板编程、数据处理的一整套功能。
- 这也意味着Django模块之间紧密耦合,开发者需要学习Django自己定义的这一整套技术。
(2)特点
[1]完善的文档
- 经过10多年的发展和完善,Django有广泛的应用和完善的在线文档,开发者遇到问题时可以搜索在线文档寻求解决方案。
[2]集成数据访问组件
- Django的Model层自带数据库ORM组件,使开发者无须学习其他数据库访问技术(dbi、SQLAlchemy等)。
[3]强大的URL映射技术
- Django使用正则表达式管理URL映射,因此给开发者带来了极高的灵活性。
[4]后台管理系统自动生成
- 开发者只需通过简单的几行配置和代码就可以实现完整的后台数据管理Web控制台。
[5]错误信息非常完整
- 在开发调试过程中如果出现运行异常,则Django可以提供非常完整的错误信息帮助开发者定位问题,比如缺少xxx组件的配置引用等,这样可以使开发者马上改正错误。
(3)组成结构
- Django是遵循MVC架构的Web开发框架,其主要由以下几部分组成。
- 管理工具(Management):一套内置的创建站点、迁移数据、维护静态文件的命令工具。
- 模型(Model):提供数据访问接口和模块,包括数据字段、元数据、数据关系等的定义及操作。
- 视图(View):Django的视图层封装了HTTP Request和Response的一系列操作和数据流,其主要功能包括URL映射机制、绑定模板等。
- 模板(Template):是一套Django自己的页面渲染模板语言,用若干内置的tags和filters定义页面的生成方式。
- 表单(Form):通过内置的数据类型和控件生成HTML表单。
- 管理站(Admin):通过声明需要管理的Model,快速生成后台数据管理网站。
(4)总结
- 大而全
- 自带的功能非常的多
- 但是有时候会略显笨重
- 类似于'航空母舰'
【2】Flask
(1)介绍
- Flask是Python Web框架族里比较年轻的一个,于2010年出现,这使得它吸收了其他框架的优点,并且把自己的主要领域定义在了微小项目上。
- 同时,它是可扩展的,Flask让开发者自己选择用什么数据库插件存储他们的数据。
- 很多功能简单但性能卓越的网站就是基于Flask框架而搭建的,比如httpbin.org就是一个功能简单但性能强大的HTTP测试项目。
- Flask是一个面向简单需求和小型应用的微框架。
(2)特点
[1]内置开发服务器和调试器
- 网络程序调试是在将编制好的网站投入实际运行前,用手工或编译程序等方法进行测试,修正语法错误和逻辑错误的过程。
- 有经验的开发者都知道,这是保证网站系统能够正式应用的必要步骤。
- Flask 自带的开发服务器使开发者在调试程序时无须再安装其他任何网络服务器,比如Tomcat、JBoss、Apache等。
- Flask默认处于调试状态,使得运行中的任何错误会同时向两个目标发送信息:
- 一个是Python Console,即启动Python程序的控制台;
- 另一个是HTTP客户端,即Flask开发服务器将调试信息传递给了客户端。
[2]与Python单元测试功能无缝衔接
- 单元测试是对最小软件开发单元的测试,其重点测试程序的内部结构,主要采用白盒测试方法,由开发人员负责。
- 单元测试的主要目标是保证函数在给定的输入状态下,能够得到预想的输出,在不符合要求时能够提醒开发人员进行检查。
- Flask提供了一个与Python自带的单元测试框架unitest无缝衔接的测试接口,即Flask对象的test_client()函数。
- 通过test_client()函数,测试程序可以模拟进行HTTP访问的客户端来调用Flask路由处理函数,并且获取函数的输出来进行自定义的验证。
[3]使用Jinja2模板
- 将HTML页面与后台应用程序联系起来一直是网站程序框架的一个重要目标。
- Flask通过使用Jinja2模板技术解决了这个问题。
- Jinja2是一个非常灵活的HTML模板技术,它是从Django模板发展而来的,但是比Django模板使用起来更加自由且更加高效。
- Jinja2模板使用配制的语义系统,提供灵活的模板继承技术,自动抗击XSS跨站攻击并且易于调试。
[5]完全兼容WSGI 1.0标准
- WSGI(Web Server Gateway Interface)具有很强的伸缩性且能运行于多线程或多进程环境下,因为Python线程全局锁的存在,使得WSGI的这个特性至关重要。
- WSGI已经是Python界的一个主要标准,各种大型网路服务器对其都有良好的支持。
- WSGI位于Web应用程序与Web服务器之间,与WSGI完全兼容使得Flask能够配置到各种大型网络服务器中。
[6]基于Unicode编码
- Flask是完全基于Unicode的。这对制作非纯ASCII字符集的网站来说非常方便。
- HTTP本身是基于字节的,也就是说任何编码格式都可以在HTTP中传输。
- 但是,HTTP要求在HTTP Head中显式地声明在本次传输中所应用的编码格式。
- 在默认情况下,Flask会自动添加一个UTF-8编码格式的HTTP Head,使程序员无须担心编码的问题。
(3)总结
- 小而精
- 自带的功能非常的少
- 但是第三方模块非常的多
- 类似于'游骑兵'
- flask的第三方模块加到一起甚至比django还多
- 并且也越来越像django
- flask由于过多的依赖于第三方模块
- 有时候也会受制于第三方模块
【3】Tornado
(1)介绍
- Tornado是使用Python编写的一个强大的可扩展的Web服务器。
- 它在处理高网络流量时表现得足够强健,却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。
- Tornado作为FriendFeed网站的基础框架,于2009年9月10日发布,目前已经获得了很多社区的支持,并且在一系列不同的场合中得到应用。
- 除FriendFeed和Facebook外,还有很多公司在生产上转向Tornado,包括Quora、Turntable.fm、Bit.ly、Hipmunk及MyYearbook等。
(2)特点
- 完备的Web框架:与Django、Flask等一样,Tornado也提供了URL路由映射、Request上下文、基于模板的页面渲染技术等开发Web应用的必备工具。
- 是一个高效的网络库,性能与Twisted、Gevent等底层Python框架相媲美:提供了异步I/O支持、超时事件处理。这使得Tornado除了可以作为Web应用服务器框架,还可以用来做爬虫应用、物联网关、游戏服务器等后台应用。
- 提供高效HTTPClient:除了服务器端框架,Tornado还提供了基于异步框架的HTTP客户端。
- 提供高效的内部HTTP服务器:虽然其他Python网络框架(Django、Flask)也提供了内部HTTP服务器,但它们的HTTP服务器由于性能原因只能用于测试环境。而Tornado的HTTP服务器与Tornado异步调用紧密结合,可以直接用于生产环境。
- 完备的WebSocket支持:WebSocket是HTML5的一种新标准,实现了浏览器与服务器之间的双向实时通信。
(3)总结
- 异步非阻塞框架
- 速度极快
- 常被用作大型站点的接口服务框架
- 甚至可以用于充当游戏服务器
【4】Fastapi
(1)介绍
- FastAPI 是一个现代 Web 框架,速度相对较快,用于基于标准 Python 类型提示使用 Python 3.7+ 构建 API。
- FastAPI还帮助我们自动为我们的Web服务生成文档,以便其他开发人员可以快速了解如何使用它。
- FastAPI 具有许多功能,例如它可以显着提高开发速度,还可以减少代码中的人为错误。
- 它很容易学习并且完全可以用于生产。
- FastAPI 与众所周知的 API 标准(即OpenAPI 和JSON schema)完全兼容。
(2)特点
[1]自动文档
- FastAPI 使用 OpenAPI 标准自动生成交互式 API 文档。
- 可以通过访问应用程序中的特定端点来访问此文档,这使得理解和测试 API 变得非常容易,而无需手动编写大量文档。
[2]Python 类型提示
- FastAPI 的突出功能之一是它使用 Python 类型提示。
- 通过使用类型提示注释函数参数和返回类型,不仅可以提高代码可读性,还可以使 FastAPI 自动验证传入数据并生成准确的 API 文档。
- 此功能使我们的代码不易出错并且更加自我记录。
[3]数据验证
- FastAPI 使用 Pydantic 模型进行数据验证。
- 可以使用 Pydantic 的架构和验证功能定义数据模型。
- 这可确保传入数据自动验证、序列化和反序列化,从而降低在应用程序中处理无效数据的风险。
[4]异步支持
- 随着Python异步编程的兴起,FastAPI完全拥抱异步操作。
- 可以使用Python的async和await关键字来编写异步端点,使其非常适合处理I/O密集型任务并提高应用程序的整体响应能力。
[5]依赖注入
- FastAPI 支持依赖注入,允许声明端点的依赖关系。
- 这有助于保持代码模块化、可测试和可维护。
- 我们可以将数据库连接、身份验证等依赖项无缝地注入到的路由中。
[6]安全功能
- FastAPI 包含各种开箱即用的安全功能,例如对 OAuth2、JWT(JSON Web 令牌)的支持以及请求数据的自动验证,以防止 SQL 注入和跨站点脚本 (XSS) 攻击等常见安全漏洞。
补充:Python框架官网(部分)
框架的核心逻辑几乎是一致的 我们在学习的时候只需要先学会一种之后就可以触类旁通
- Django框架官网:https://www.djangoproject.com/
- Flask框架官网:https://flask.palletsprojects.com/en/3.0.x/
- Fastapi框架官网:https://fastapi.tiangolo.com/
- Pyramind框架官网:https://trypyramid.com/
- Tornado框架官网:https://www.tornadoweb.org/en/stable/
- Sanic框架官网:https://github.com/sanic-org/sanic
- Fastapi框架官网:https://fastapi.tiangolo.com/
- Aiohttp框架官网:https://docs.aiohttp.org/en/stable/
补充:Django框架版本
- Django 是一个高级的Python Web框架,由荷兰人Armin Ronacher创建。
- 随着版本的迭代和功能的不断优化,Django在处理异步请求方面也有了显著的进步。
【1】Django1.x
- 默认不支持异步
- Django 1.x主要集中在传统的Web开发上,其设计思想倾向于同步HTTP请求处理。
- 默认情况下,并未内置对异步编程的支持,开发者若要在Django 1.x中实现异步处理,通常需要借助第三方库如
django-celery
或django-tornado
等来结合其他异步框架(如Celery、Tornado等)来实现后台任务的异步执行。
【2】Django2.x
- 默认不支持异步
- 在Django 2.x版本中,虽然核心框架并未直接提供对异步HTTP请求的支持,但已经开始引入一些异步相关的新特性和API,比如
asgi
(Asynchronous Server Gateway Interface) 标准的初步支持。 - 开发者可以通过安装第三方ASGI服务器(如
daphne
或uvicorn
),配合channels
库使用,来实现Websockets和消息队列等场景下的部分异步功能。
【3】Django3.x
- 自带异步功能
- Django 3.x标志着其正式对异步编程的支持,它引入了
channels
框架作为标准库的一部分,实现了全栈的WebSocket支持以及与asyncio
的集成,使得开发者可以直接在视图层、消费者层以及中间件层面编写异步代码,提供了ASGI
和HTTP/2
协议的底层支持。 - 此外,
django-redis
、django-socketio
等第三方库也进一步丰富了异步应用的构建能力。
【4】Django4.x
- 在Django 4.x版本之后,异步功能得到了持续加强和完善。
- 例如,在4.0中,
channels
框架进行了重大重构,使其更加轻量级和模块化,同时引入了websockets
库作为默认WebSocket支持,大大简化了开发者配置和使用的复杂度。 - 此外,对于长期支持计划(LTS)版本,Django会确保异步相关的API和工具在后续更新中得到稳定且兼容的维护和支持,以满足现代Web应用对高性能、低延迟的需求。