fastapi入门
好的,我将为您生成一个更详细、易于理解的 FastAPI 入门学习文档,特别是对复杂概念(如依赖注入)进行深入解释,帮助您在没有太多基础的情况下也能顺利学习和掌握 FastAPI。
FastAPI 入门学习文档
目录
- 简介
- 环境搭建
- 2.1 安装 Python
- 2.2 创建虚拟环境
- 2.3 安装 FastAPI 和 Uvicorn
- FastAPI 基础
- 3.1 创建第一个 FastAPI 应用
- 3.2 路径操作(路由)
- 3.3 请求参数
- 3.4 数据模型(Pydantic 模型)
- 3.5 响应模型
- 深入理解 FastAPI
- 4.1 依赖注入(Dependency Injection)
- 4.2 中间件
- 4.3 错误处理
- 4.4 异步支持
- 与数据库集成
- 5.1 使用 SQLAlchemy
- 5.2 使用 SQLModel(推荐)
- 5.3 数据库迁移
- 安全与认证
- 6.1 OAuth2 与 JWT
- 6.2 基于表单的认证
- 部署 FastAPI 应用
- 7.1 使用 Uvicorn
- 7.2 使用 Gunicorn 和 Uvicorn Workers
- 7.3 Docker 部署
- 附加资源
- 总结
1. 简介
FastAPI 是一个用于构建 API 的现代、快速(高性能)的 Web 框架,基于 Python 3.6+ 的类型提示(type hints)。它具有以下特点:
- 高性能:性能与 Node.js 和 Go 等语言的框架相当,适合高并发、高性能的应用。
- 快速开发:减少代码量,提高开发效率,支持自动生成文档。
- 类型安全:利用 Python 的类型提示,提供更好的代码补全和类型检查,减少错误。
- 自动文档:自动生成交互式 API 文档,基于 OpenAPI(Swagger)和 JSON Schema。
- 异步支持:原生支持异步编程(
async
/await
),提升高并发场景下的性能。
2. 环境搭建
在开始使用 FastAPI 之前,需要进行环境的搭建。
2.1 安装 Python
首先,确保已安装 Python 3.6 及以上版本。
-
检查 Python 版本:
python --version
如果输出的版本号小于 3.6,请前往 Python 官网 下载并安装最新版本。
2.2 创建虚拟环境
使用虚拟环境可以隔离项目的依赖,避免与其他项目的库发生冲突。
-
创建虚拟环境:
# 创建名为 venv 的虚拟环境 python -m venv venv
-
激活虚拟环境:
-
Windows:
venv\Scripts\activate
-
macOS/Linux:
source venv/bin/activate
激活后,命令行前会出现
(venv)
,表示已进入虚拟环境。 -
2.3 安装 FastAPI 和 Uvicorn
-
安装 FastAPI:
pip install fastapi
-
安装 Uvicorn:
Uvicorn 是一个用于运行 ASGI 应用的高性能服务器。
pip install "uvicorn[standard]"
3. FastAPI 基础
3.1 创建第一个 FastAPI 应用
-
创建
main.py
文件:from fastapi import FastAPIapp = FastAPI()@app.get("/") async def read_root():return {"message": "Hello, FastAPI!"}
解释:
-
导入 FastAPI 类:
from fastapi import FastAPI
-
创建 FastAPI 应用实例:
app = FastAPI()
-
定义路径操作(路由):
@app.get("/") async def read_root():return {"message": "Hello, FastAPI!"}
@app.get("/")
是一个装饰器,表示当用户访问根路径/
时,执行下面的read_root
函数。async def
定义了一个异步函数,后续会详细介绍异步编程。- 函数返回一个字典,FastAPI 会自动将其转换为 JSON 格式的响应。
-
-
运行应用:
在终端中,运行以下命令启动应用:
uvicorn main:app --reload
解释:
uvicorn
是运行 ASGI 应用的服务器。main:app
指的是main.py
文件中的app
对象。--reload
选项使得应用在代码更改时自动重新加载,方便开发。
-
访问应用:
打开浏览器,访问 http://127.0.0.1:8000/,应看到以下 JSON 响应:
{"message": "Hello, FastAPI!" }
-
查看自动生成的文档:
FastAPI 提供了自动生成的 API 文档:
- Swagger UI:http://127.0.0.1:8000/docs
- ReDoc:http://127.0.0.1:8000/redoc
在这些页面上,你可以看到应用的 API 结构,并进行交互式测试。
3.2 路径操作(路由)
路径操作用于定义应用响应特定路径和 HTTP 方法的函数。
-
定义路径参数:
@app.get("/items/{item_id}") async def read_item(item_id: int):return {"item_id": item_id}
解释:
{item_id}
表示路径参数,item_id
的值将从请求的 URL 中提取。- 在函数参数中,声明
item_id: int
,表示item_id
的类型为整数。 - FastAPI 会自动进行类型转换和验证,如果传入的
item_id
不能转换为整数,将返回一个 422 错误(Unprocessable Entity)。
-
访问示例:
访问 http://127.0.0.1:8000/items/5,将返回:
{"item_id": 5 }
-
指定请求方法:
FastAPI 支持以下 HTTP 方法:
@app.get()
:处理 GET 请求@app.post()
:处理 POST 请求@app.put()
:处理 PUT 请求@app.delete()
:处理 DELETE 请求@app.patch()
:处理 PATCH 请求
3.3 请求参数
请求参数包括路径参数、查询参数和请求体。
-
查询参数:
@app.get("/items/") async def read_items(skip: int = 0, limit: int = 10):return {"skip": skip, "limit": limit}
解释:
skip: int = 0
和limit: int = 10
是查询参数,具有默认值。- 如果在 URL 中提供了
skip
和limit
,将覆盖默认值。 - 查询参数是可选的,如果未提供,则使用默认值。
-
访问示例:
-
访问 http://127.0.0.1:8000/items/?skip=5&limit=20,返回:
{"skip": 5,"limit": 20 }
-
-
路径参数和查询参数组合:
@app.get("/users/{user_id}/items/{item_id}") async def read_user_item(user_id: int, item_id: str, q: str = None):item = {"user_id": user_id, "item_id": item_id}if q:item["q"] = qreturn item
解释:
user_id
和item_id
是路径参数,从 URL 中提取。q
是查询参数,默认为None
,表示可选。- 根据是否提供查询参数
q
,返回的数据会有所不同。
3.4 数据模型(Pydantic 模型)
FastAPI 使用 Pydantic 来定义数据模型和进行数据验证。
-
安装 Pydantic:
Pydantic 是 FastAPI 的依赖,一般情况下已经安装,无需单独安装。
-
定义数据模型:
from pydantic import BaseModelclass Item(BaseModel):name: strdescription: str = Noneprice: floattax: float = None
解释:
-
继承自
BaseModel
:Pydantic 的所有模型都需要继承自
BaseModel
。 -
定义字段和类型:
name: str
:必须的字符串字段。description: str = None
:可选的字符串字段,默认为None
。price: float
:必须的浮点数字段。tax: float = None
:可选的浮点数字段。
-
类型提示:
使用类型提示(Type Hints)定义字段的类型,Pydantic 会根据这些类型进行数据验证和解析。
-
-
接收请求体:
@app.post("/items/") async def create_item(item: Item):return item
解释:
- 函数参数
item: Item
指定请求体将被解析为Item
类型的对象。 - FastAPI 会自动从请求体中读取 JSON 数据,并转换为
Item
对象。 - 如果请求体的数据不符合
Item
模型的定义(如缺少必须字段、类型错误等),FastAPI 会返回 422 错误,指出具体的验证错误。
- 函数参数
-
请求示例:
发送 POST 请求到
/items/
,请求体为:{"name": "Apple","description": "A juicy fruit","price": 1.2,"tax": 0.1 }
服务器将返回相同的数据,表示成功接收。
3.5 响应模型
可以使用响应模型来控制返回的数据结构。
-
指定响应模型:
@app.post("/items/", response_model=Item) async def create_item(item: Item):return item
解释:
response_model=Item
指定了响应的数据模型为Item
。- 即使函数内部返回了更多数据,FastAPI 也只会根据
Item
模型来过滤和返回字段。
-
示例:
@app.post("/items/", response_model=Item) async def create_item(item: Item):return {"name": item.name, "description": item.description, "price": item.price, "tax": item.tax, "id": 123}
即使返回的字典中包含了
id
字段,响应中也不会包含该字段,因为Item
模型中未定义id
。
4. 深入理解 FastAPI
4.1 依赖注入(Dependency Injection)
依赖注入(Dependency Injection)是一种设计模式,用于将组件的依赖关系从内部移到外部,使得组件更加灵活和可测试。
在 FastAPI 中,依赖注入用于复用代码、共享逻辑,如验证、数据库连接等。
4.1.1 什么是依赖注入
-
传统方式:
在函数内部直接调用其他函数或创建对象。
def process():db = get_db()data = db.fetch_data()return data
缺点:
- 难以复用代码。
- 不易于测试和维护。
-
依赖注入方式:
将依赖关系作为参数传入函数,由外部提供。
def process(db = Depends(get_db)):data = db.fetch_data()return data
优点:
- 提高代码复用性。
- 方便测试和替换依赖项。
- FastAPI 会自动管理依赖项的创建和销毁。
4.1.2 FastAPI 中的依赖注入
-
使用
Depends
声明依赖项:from fastapi import Dependsdef get_db():db = DatabaseConnection()try:yield dbfinally:db.close()@app.get("/items/") async def read_items(db = Depends(get_db)):items = db.fetch_items()return items
解释:
get_db
函数是一个依赖项,返回一个数据库连接对象。- 在
read_items
函数中,使用db = Depends(get_db)
声明了对get_db
的依赖。 - FastAPI 会在调用
read_items
时,自动执行get_db
,将返回的db
对象作为参数传入read_items
。
-
依赖项可以是同步或异步的函数:
- 同步函数:普通的
def
函数。 - 异步函数:使用
async def
定义。
- 同步函数:普通的
-
依赖项中的
yield
:- 当依赖项函数使用
yield
时,表示这是一个 上下文管理器,在请求结束后会执行finally
部分。 - 这对于需要在请求结束后进行清理的操作(如关闭数据库连接)非常有用。
- 当依赖项函数使用
-
多级依赖:
依赖项本身也可以依赖其他依赖项,形成依赖树。
def get_token_header(x_token: str = Header(...)):if x_token != "fake-super-secret-token":raise HTTPException(status_code=400, detail="Invalid X-Token header")def get_db(token = Depends(get_token_header)):db = DatabaseConnection()yield dbdb.close()@app.get("/items/") async def read_items(db = Depends(get_db)):items = db.fetch_items()return items
解释:
get_token_header
依赖从请求头中获取X-Token
,并进行验证。get_db
依赖get_token_header
,只有在验证通过后才会获取数据库连接。read_items
依赖get_db
,最终形成依赖链。
4.1.3 示例:公共参数
-
定义一个依赖项,提供公共查询参数:
from typing import Optionaldef common_parameters(q: Optional[str] = None, skip: int = 0, limit: int = 10):return {"q": q, "skip": skip, "limit": limit}@app.get("/items/") async def read_items(commons: dict = Depends(common_parameters)):return commons@app.get("/users/") async def read_users(commons: dict = Depends(common_parameters)):return commons
解释:
common_parameters
函数定义了常用的查询参数q
、skip
、limit
。- 在路径操作函数中,使用
commons: dict = Depends(common_parameters)
声明依赖。 - FastAPI 会自动执行
common_parameters
,并将返回值(字典)传递给路径操作函数。 - 这样,多个路径操作函数可以共享相同的查询参数逻辑,避免重复代码。
4.1.4 依赖注入的应用场景
- 数据库连接和会话管理
- 验证和授权
- 配置和环境变量
- 日志记录
- 缓存
理解中间件(Middleware)对于构建功能丰富且高效的 FastAPI 应用至关重要。为了帮助您更好地掌握这一概念,我将重新整理并详细解释 4.2 中间件 部分,同时保持整体文档的平衡和简洁。
4.2 中间件
中间件(Middleware)是在 请求(Request)和 响应(Response)之间执行的函数。它们可以用于执行一些在每个请求或响应中重复的任务,如日志记录、认证、修改请求或响应等。可以将中间件类比为**“中间人”**,它们在请求到达路径操作函数之前或响应返回给客户端之前进行处理。
4.2.1 什么是中间件?
- 定义: 中间件是在请求和响应过程中拦截并处理这些请求和响应的组件。
- 作用:
- 日志记录: 记录每个请求的详细信息,如请求路径、方法、处理时间等。
- 认证与授权: 检查请求是否具有访问特定资源的权限。
- 修改请求或响应: 如添加自定义头部、处理跨域请求(CORS)等。
- 错误处理: 捕获并处理全局错误,统一返回错误响应。
4.2.2 FastAPI 中的中间件工作原理
在 FastAPI 中,中间件是使用装饰器 @app.middleware("http")
注册的异步函数。当一个请求到达 FastAPI 应用时,所有注册的中间件会按注册顺序依次执行,处理请求并在响应返回时再次按相反的顺序处理响应。
中间件的执行流程:
- 请求到达中间件: 请求首先由第一个中间件接收。
- 中间件预处理: 中间件可以在调用下一个处理程序之前,对请求进行处理(如记录日志、验证认证)。
- 调用下一个处理程序: 使用
call_next(request)
将请求传递给下一个中间件或最终的路径操作函数。 - 响应返回中间件: 响应通过中间件链返回,中间件可以在返回响应之前进行后处理(如修改响应头)。
- 最终响应返回客户端: 经过所有中间件处理后的响应被发送给客户端。
4.2.3 中间件函数的组成部分
一个典型的 FastAPI 中间件函数包含以下部分:
- 装饰器
@app.middleware("http")
: 用于注册中间件函数,并指定其作用于 HTTP 请求。 - 请求对象(
Request
): 包含了请求的所有信息,如路径、方法、头部、体等。 call_next
函数: 一个特殊的函数,用于将请求传递给下一个中间件或最终的路径操作函数。- 响应对象(
Response
): 由路径操作函数或下一个中间件生成的响应。
4.2.4 详细示例:记录请求处理时间
让我们通过一个具体的示例来深入理解中间件的工作原理。
示例代码:
from fastapi import FastAPI, Request
import timeapp = FastAPI()@app.middleware("http")
async def add_process_time_header(request: Request, call_next):"""中间件函数:记录请求的处理时间,并将其添加到响应头中。参数:- request: Request 对象,包含请求的详细信息。- call_next: 函数,用于调用下一个中间件或路径操作函数。返回:- response: 经过处理的响应对象。"""start_time = time.time() # 记录请求开始时间response = await call_next(request) # 将请求传递给下一个处理程序process_time = time.time() - start_time # 计算处理时间response.headers["X-Process-Time"] = f"{process_time:.4f} seconds" # 添加处理时间到响应头return response # 返回修改后的响应
解释:
-
注册中间件:
@app.middleware("http") async def add_process_time_header(request: Request, call_next):...
@app.middleware("http")
装饰器告诉 FastAPI 这是一个 HTTP 中间件。- 中间件函数必须接收两个参数:
request
:当前的请求对象。call_next
:用于将请求传递给下一个中间件或路径操作函数的函数。
-
记录开始时间:
start_time = time.time()
- 使用
time.time()
记录当前时间,以计算处理请求所需的时间。
- 使用
-
调用下一个处理程序:
response = await call_next(request)
call_next(request)
将请求传递给下一个中间件或最终的路径操作函数。- 使用
await
确保异步调用,防止阻塞。
-
计算处理时间:
process_time = time.time() - start_time
- 计算从记录开始时间到收到响应的时间差。
-
添加处理时间到响应头:
response.headers["X-Process-Time"] = f"{process_time:.4f} seconds"
- 将处理时间作为自定义头部
X-Process-Time
添加到响应中。
- 将处理时间作为自定义头部
-
返回响应:
return response
- 返回修改后的响应对象。
路径操作函数示例:
为了完整演示中间件的作用,我们创建一个简单的路径操作函数:
@app.get("/items/{item_id}")
async def read_item(item_id: int):"""路径操作函数:返回指定 item_id 的项目信息。"""return {"item_id": item_id, "name": f"Item {item_id}"}
完整示例代码:
from fastapi import FastAPI, Request
import timeapp = FastAPI()@app.middleware("http")
async def add_process_time_header(request: Request, call_next):"""中间件函数:记录请求的处理时间,并将其添加到响应头中。"""start_time = time.time()response = await call_next(request)process_time = time.time() - start_timeresponse.headers["X-Process-Time"] = f"{process_time:.4f} seconds"return response@app.get("/items/{item_id}")
async def read_item(item_id: int):"""路径操作函数:返回指定 item_id 的项目信息。"""return {"item_id": item_id, "name": f"Item {item_id}"}
运行应用并测试:
-
启动应用:
uvicorn main:app --reload
-
访问路径操作函数:
打开浏览器,访问 http://127.0.0.1:8000/items/5,您将看到以下 JSON 响应:
{"item_id": 5,"name": "Item 5" }
-
查看响应头:
使用浏览器的开发者工具或工具如 Postman,查看响应头,您会看到
X-Process-Time
头部,显示请求处理所需的时间。例如:X-Process-Time: 0.0002 seconds
4.2.5 中间件的执行顺序
理解中间件的执行顺序有助于正确设计和调试应用。中间件按照注册顺序依次执行,响应则按相反的顺序返回。
示例:
假设我们有两个中间件 middleware_one
和 middleware_two
,它们按以下顺序注册:
@app.middleware("http")
async def middleware_one(request: Request, call_next):print("Middleware One: Before")response = await call_next(request)print("Middleware One: After")return response@app.middleware("http")
async def middleware_two(request: Request, call_next):print("Middleware Two: Before")response = await call_next(request)print("Middleware Two: After")return response
执行流程:
-
请求到达
middleware_one
:Middleware One: Before
-
请求传递到
middleware_two
:Middleware Two: Before
-
请求传递到路径操作函数:
# 执行路径操作函数
-
响应返回到
middleware_two
:Middleware Two: After
-
响应返回到
middleware_one
:Middleware One: After
控制台输出:
Middleware One: Before
Middleware Two: Before
Middleware Two: After
Middleware One: After
客户端请求|v
+------------------+
| 中间件1 (请求) |
+------------------+|v
+------------------+
| 中间件2 (请求) |
+------------------+|v
+------------------+
| 路径操作函数 (处理) |
+------------------+|v
+------------------+
| 中间件2 (响应) |
+------------------+|v
+------------------+
| 中间件1 (响应) |
+------------------+|v返回响应给客户端
4.2.6 详细示例:身份认证中间件
让我们创建一个中间件,检查每个请求是否包含特定的认证头部 X-API-KEY
,如果没有则返回 401 未授权错误。
示例代码:
from fastapi import FastAPI, Request, HTTPException
from starlette.status import HTTP_401_UNAUTHORIZEDapp = FastAPI()API_KEY = "mysecretapikey"@app.middleware("http")
async def verify_api_key(request: Request, call_next):"""中间件函数:验证请求是否包含正确的 X-API-KEY 头部。"""api_key = request.headers.get("X-API-KEY")if api_key != API_KEY:raise HTTPException(status_code=HTTP_401_UNAUTHORIZED,detail="Invalid or missing API Key",)response = await call_next(request)return response@app.get("/protected")
async def protected_route():"""受保护的路径操作函数,只有通过中间件验证的请求才能访问。"""return {"message": "You have access to this protected route!"}
解释:
-
定义 API 密钥:
API_KEY = "mysecretapikey"
- 这是预定义的密钥,客户端必须在请求头中提供此密钥才能访问受保护的资源。
-
注册中间件:
@app.middleware("http") async def verify_api_key(request: Request, call_next):...
- 中间件函数
verify_api_key
将验证每个请求的X-API-KEY
头部。
- 中间件函数
-
获取并验证 API 密钥:
api_key = request.headers.get("X-API-KEY") if api_key != API_KEY:raise HTTPException(status_code=HTTP_401_UNAUTHORIZED,detail="Invalid or missing API Key",)
- 从请求头中获取
X-API-KEY
。 - 如果密钥不匹配,抛出一个 HTTP 401 异常,表示未授权。
- 从请求头中获取
-
传递请求并返回响应:
response = await call_next(request) return response
- 如果密钥验证通过,将请求传递给下一个中间件或路径操作函数。
- 最终返回响应。
-
定义受保护的路径操作函数:
@app.get("/protected") async def protected_route():return {"message": "You have access to this protected route!"}
- 只有在中间件验证通过后,才能访问此路径。
测试:
-
未提供 API 密钥:
-
请求:
curl -X GET "http://127.0.0.1:8000/protected"
-
响应:
{"detail": "Invalid or missing API Key" }
-
-
提供正确的 API 密钥:
-
请求:
curl -X GET "http://127.0.0.1:8000/protected" -H "X-API-KEY: mysecretapikey"
-
响应:
{"message": "You have access to this protected route!" }
-
4.2.7 中间件的最佳实践
- 保持中间件简洁: 中间件应专注于一个特定的任务,避免过于复杂。
- 正确处理异步: 使用
async
和await
关键字确保中间件不会阻塞事件循环,特别是在处理 I/O 密集型任务时。 - 错误处理: 在中间件中捕获可能的异常,并返回适当的错误响应,避免应用崩溃。
- 顺序注册: 中间件的注册顺序影响它们的执行顺序。确保按照逻辑顺序注册中间件,例如先进行认证,再进行日志记录。
- 避免过多依赖: 尽量减少中间件之间的依赖关系,保持它们的独立性,便于维护和测试。
4.3 错误处理
FastAPI 提供了简洁的错误处理方式,可以自定义异常和响应。
4.3.1 抛出 HTTPException
-
示例:
from fastapi import HTTPException@app.get("/items/{item_id}") async def read_item(item_id: int):if item_id not in items_db:raise HTTPException(status_code=404, detail="Item not found")return items_db[item_id]
解释:
HTTPException
用于在路径操作函数中抛出 HTTP 错误。status_code
指定 HTTP 状态码。detail
提供错误的详细信息。
4.3.2 自定义异常处理器
-
示例:处理自定义异常
from fastapi import Request from fastapi.responses import JSONResponseclass UnicornException(Exception):def __init__(self, name: str):self.name = name@app.exception_handler(UnicornException) async def unicorn_exception_handler(request: Request, exc: UnicornException):return JSONResponse(status_code=418,content={"message": f"Oh no! {exc.name} did something wrong."},)@app.get("/unicorns/{name}") async def read_unicorn(name: str):if name == "yolo":raise UnicornException(name=name)return {"unicorn_name": name}
解释:
- 定义了一个自定义异常
UnicornException
。 - 使用
@app.exception_handler
注册异常处理器,当抛出UnicornException
时,执行处理器函数。 - 在处理器中,返回自定义的响应。
- 定义了一个自定义异常
4.4 异步支持
FastAPI 原生支持异步编程,允许使用 async
和 await
关键字定义异步函数。
4.4.1 什么是异步编程
- 同步编程:
- 代码按顺序执行,一个任务完成后才能执行下一个任务。
- 在 I/O 操作(如网络请求、文件读写)时,程序会等待操作完成,导致阻塞。
- 异步编程:
- 通过事件循环(Event Loop)调度任务,允许在等待 I/O 操作时执行其他任务。
- 提高程序的并发能力,适合 I/O 密集型的应用。
4.4.2 在 FastAPI 中使用异步函数
-
定义异步路径操作函数:
@app.get("/async-items/") async def read_async_items():await some_async_task()return [{"item_id": "Foo"}]
解释:
- 使用
async def
定义异步函数。 - 可以使用
await
调用其他异步函数。
- 使用
-
注意事项:
- 如果函数不涉及 I/O 操作,可以使用普通的同步函数(
def
)。 - 不要在同步函数中调用异步函数(即不要在同步函数中使用
await
)。
- 如果函数不涉及 I/O 操作,可以使用普通的同步函数(
4.4.3 异步库的使用
-
异步数据库驱动:
- 使用支持异步的数据库驱动,如
asyncpg
、databases
等。
- 使用支持异步的数据库驱动,如
-
示例:
from databases import Databasedatabase = Database("sqlite:///./test.db")@app.on_event("startup") async def startup():await database.connect()@app.on_event("shutdown") async def shutdown():await database.disconnect()@app.get("/items/") async def read_items():query = "SELECT * FROM items"return await database.fetch_all(query)
解释:
- 在应用启动和关闭时,连接和断开数据库。
- 使用异步的数据库查询,提高性能。
-
@app.on_event的作用
- @app.on_event是FastAPI提供的一个装饰器,用于定义在特定事件发生时执行的函数。
- FastAPI的声明周期时间包括:
startup
:在应用启动时触发,仅执行一次。shutdown
:在应用关闭时触发,仅执行一次。
startup
事件- 当FastAPI应用启动时会触发
startup
事件。 - 可以在这个时间中执行一些初始化操作,例如:
- 连接数据库。
- 初始化缓存。
- 加载配置文件。
- 初始化全局变量或状态。
- 当FastAPI应用启动时会触发
shutdown
事件- 当FastAPI应用关闭时会触发
shutdown
事件。 - 通常用于清理资源,例如:
- 关闭数据库连接。
- 清理缓存。
- 停止后台任务。
- 当FastAPI应用关闭时会触发
示例操作:
from fastapi import FastAPI
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmakerapp = FastAPI()# 配置异步数据库引擎
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
engine = create_async_engine(DATABASE_URL, echo=True)
SessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False)# 应用启动时连接数据库
@app.on_event("startup")
async def startup():print("Connecting to the database...")# 在这里可以进行一些额外的初始化逻辑,例如检查数据库状态等# 应用关闭时断开数据库连接
@app.on_event("shutdown")
async def shutdown():print("Disconnecting from the database...")await engine.dispose()
解释:
@app.on_event("startup")
:- 在应用启动时,打印 “Connecting to the database…”,并可添加其他逻辑(如测试数据库连接)。
@app.on_event("shutdown")
:- 在应用关闭时,打印 “Disconnecting from the database…”,并调用
engine.dispose()
释放数据库资源。
- 在应用关闭时,打印 “Disconnecting from the database…”,并调用
5. 与数据库集成
5.1 使用 SQLAlchemy
SQLAlchemy 是 Python 中广泛使用的 ORM(对象关系映射)库,可以将数据库表映射为 Python 类。
5.1.1 安装依赖
pip install sqlalchemy
5.1.2 创建数据库引擎
from sqlalchemy import create_engineDATABASE_URL = "sqlite:///./test.db"engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False}
)
解释:
DATABASE_URL
指定了数据库的连接 URL,此处使用 SQLite 数据库,文件名为test.db
。connect_args={"check_same_thread": False}
是 SQLite 特有的参数,允许多个线程访问同一个数据库连接。
5.1.3 创建数据库会话
from sqlalchemy.orm import sessionmakerSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
解释:
SessionLocal
是一个本地的数据库会话类,每个请求都应创建一个新的会话实例。
5.1.4 定义模型
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, FloatBase = declarative_base()class Item(Base):__tablename__ = "items"id = Column(Integer, primary_key=True, index=True)name = Column(String, index=True)description = Column(String, nullable=True)price = Column(Float)tax = Column(Float, nullable=True)
解释:
Base
是所有模型类的基类,使用declarative_base()
创建。Item
类定义了数据库中的items
表,每个属性对应一个字段。
5.1.5 创建数据库表
Base.metadata.create_all(bind=engine)
解释:
- 这行代码会在数据库中创建所有继承自
Base
的模型对应的表。
5.1.6 依赖注入数据库会话
from fastapi import Dependsdef get_db():db = SessionLocal()try:yield dbfinally:db.close()
解释:
get_db
是一个依赖项函数,返回一个数据库会话。- 使用
yield
将db
对象提供给依赖它的函数,在请求结束后自动关闭会话。
5.1.7 在路径操作中使用数据库
from sqlalchemy.orm import Session
from fastapi import Depends@app.post("/items/", response_model=schemas.Item)
async def create_item(item: schemas.ItemCreate, db: Session = Depends(get_db)):db_item = models.Item(name=item.name, description=item.description, price=item.price, tax=item.tax)db.add(db_item)db.commit()db.refresh(db_item)return db_item
解释:
db: Session = Depends(get_db)
声明了对数据库会话的依赖。- 在函数中使用
db
进行数据库操作,如添加、提交、刷新。
5.2 使用 SQLModel(推荐)
SQLModel 是一个基于 Pydantic 和 SQLAlchemy 的库,简化了模型定义,统一了数据模型和 ORM 模型。
5.2.1 安装 SQLModel
pip install sqlmodel
5.2.2 定义模型
from typing import Optional
from sqlmodel import SQLModel, Fieldclass Item(SQLModel, table=True):id: Optional[int] = Field(default=None, primary_key=True)name: strdescription: Optional[str] = Noneprice: floattax: Optional[float] = None
解释:
- 继承自
SQLModel
,并设置table=True
,表示这是一个数据库表模型。 - 使用类型提示定义字段,
Field
用于设置额外的元数据,如primary_key
。
5.2.3 创建数据库引擎
from sqlmodel import create_engineengine = create_engine("sqlite:///database.db")
5.2.4 创建数据库表
SQLModel.metadata.create_all(engine)
5.2.5 使用数据库会话
from sqlmodel import Session@app.post("/items/", response_model=Item)
def create_item(item: Item):with Session(engine) as session:session.add(item)session.commit()session.refresh(item)return item
解释:
- 使用
with Session(engine) as session
创建一个会话。 - 直接使用
item
对象进行数据库操作,无需手动转换。
5.3 数据库迁移
使用 Alembic 管理数据库迁移,跟踪数据库模式的变化。
5.3.1 安装 Alembic
pip install alembic
5.3.2 初始化 Alembic
alembic init alembic
5.3.3 配置 Alembic
-
编辑
alembic.ini
文件,设置数据库连接字符串。sqlalchemy.url = sqlite:///./test.db
-
编辑
alembic/env.py
,引入模型的元数据。from models import Base target_metadata = Base.metadata
5.3.4 创建迁移脚本
alembic revision --autogenerate -m "Initial migration"
5.3.5 应用迁移
alembic upgrade head
6. 安全与认证
6.1 OAuth2 与 JWT
使用 OAuth2 和 JWT(JSON Web Tokens)实现基于令牌的认证。
6.1.1 安装依赖
pip install python-multipart
pip install python-jose[cryptography]
pip install passlib[bcrypt]
python-multipart
:处理表单数据。python-jose
:生成和验证 JWT。passlib[bcrypt]
:处理密码哈希。
6.1.2 配置安全依赖
from fastapi.security import OAuth2PasswordBeareroauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
解释:
OAuth2PasswordBearer
指定了获取令牌的 URL(/token
)。oauth2_scheme
是一个依赖项,用于从请求中获取Authorization
头中的Bearer
令牌。
6.1.3 创建令牌
from datetime import datetime, timedelta
from jose import JWTError, jwtSECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30def create_access_token(data: dict):to_encode = data.copy()expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)to_encode.update({"exp": expire})encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)return encoded_jwt
解释:
SECRET_KEY
:用于加密和解密 JWT 的密钥,应设置为随机字符串并保密。ALGORITHM
:加密算法,通常使用HS256
。ACCESS_TOKEN_EXPIRE_MINUTES
:令牌的有效期。create_access_token
:创建 JWT,包含传入的数据和过期时间。
6.1.4 验证令牌
from fastapi import Depends, HTTPException, status
from jose import JWTError, jwtasync def get_current_user(token: str = Depends(oauth2_scheme)):credentials_exception = HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="Could not validate credentials",headers={"WWW-Authenticate": "Bearer"},)try:payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])username: str = payload.get("sub")if username is None:raise credentials_exception# 从数据库中获取用户对象user = get_user(username)if user is None:raise credentials_exceptionexcept JWTError:raise credentials_exceptionreturn user
解释:
- 使用
jwt.decode
解码令牌,获取负载数据。 - 验证令牌是否有效,是否包含
username
。 - 根据
username
获取用户对象,若不存在则抛出异常。
6.1.5 创建登录接口
from fastapi.security import OAuth2PasswordRequestForm@app.post("/token")
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):user = authenticate_user(form_data.username, form_data.password)if not user:raise HTTPException(status_code=400, detail="Incorrect username or password")access_token = create_access_token(data={"sub": user.username})return {"access_token": access_token, "token_type": "bearer"}
解释:
- 使用
OAuth2PasswordRequestForm
处理表单数据,包含username
和password
。 - 验证用户名和密码,成功后创建并返回令牌。
6.2 基于表单的认证
-
处理表单数据:
from fastapi import Form@app.post("/login") async def login(username: str = Form(...), password: str = Form(...)):# 验证用户名和密码return {"message": "Login successful"}
解释:
- 使用
Form(...)
指定参数从表单数据中获取。 - 处理登录逻辑,返回响应。
- 使用
7. 部署 FastAPI 应用
7.1 使用 Uvicorn
-
运行应用:
uvicorn main:app --host 0.0.0.0 --port 80
解释:
--host 0.0.0.0
:监听所有网络接口。--port 80
:使用 80 端口。
7.2 使用 Gunicorn 和 Uvicorn Workers
-
安装 Gunicorn:
pip install gunicorn
-
运行应用:
gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
解释:
-w 4
:启动 4 个工作进程。-k uvicorn.workers.UvicornWorker
:使用 Uvicorn 的工作进程。
7.3 Docker 部署
7.3.1 创建 Dockerfile
FROM python:3.9-slimWORKDIR /appCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txtCOPY . .CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
解释:
- 基于官方的 Python 3.9 精简版镜像。
- 复制项目文件,安装依赖。
- 使用 Uvicorn 启动应用。
7.3.2 构建 Docker 镜像
docker build -t myfastapiapp .
7.3.3 运行 Docker 容器
docker run -d -p 80:80 myfastapiapp
简单版本
以下是一个简单的 FastAPI 演示代码,帮助你理解服务器和路由的基本概念:
from fastapi import FastAPI# 创建 FastAPI 应用实例
app = FastAPI()# 定义一个根路由,返回欢迎信息
@app.get("/")
async def read_root():return {"message": "欢迎来到我的 FastAPI 应用!"}# 定义一个用户信息的路由,接收用户 ID
@app.get("/users/{user_id}")
async def read_user(user_id: int):return {"user_id": user_id, "name": "用户名称"}# 定义一个创建用户的路由,使用 POST 方法
@app.post("/users/")
async def create_user(user: dict):return {"message": "用户已创建", "user": user}# 运行应用
if __name__ == "__main__":import uvicornuvicorn.run(app, host="0.0.0.0", port=8000)
代码解析:
- 创建应用:
app = FastAPI()
创建一个 FastAPI 应用实例。 - 路由定义:
@app.get("/")
: 定义一个 GET 请求的路由,访问根 URL 返回欢迎信息。@app.get("/users/{user_id}")
: 定义一个动态路由,通过 URL 参数接收user_id
,返回该用户的 ID 和名称。@app.post("/users/")
: 定义一个 POST 请求的路由,接收用户信息并返回创建结果。
- 运行应用: 使用
uvicorn.run()
方法运行应用,监听所有地址的 8000 端口。
运行方式:
- 将代码保存为
main.py
。 - 在终端中运行
python main.py
。 - 在浏览器访问
http://localhost:8000/docs
,查看自动生成的 API 文档和测试接口。
这个简单的示例展示了 FastAPI 如何定义路由并处理请求。希望这能帮助你更好地理解相关概念!
复杂版本
好的,下面是一个简化的 FastAPI 工程示例,结构和功能与您提供的代码类似,旨在帮助您理解 FastAPI 的路由和服务器相关的知识。
项目结构
my_fastapi_app/
│
├─ main.py # 主应用文件
├─ requirements.txt # 依赖项文件
└─ routers/├─ __init__.py # 初始化模块├─ user.py # 用户相关路由└─ item.py # 项目相关路由
1. main.py
from fastapi import FastAPI
from routers import user, itemapp = FastAPI(title="My FastAPI App", version="1.0")# 将路由挂载到应用上
app.include_router(user.router, prefix="/users", tags=["Users"])
app.include_router(item.router, prefix="/items", tags=["Items"])@app.get("/", tags=["Root"])
async def read_root():return {"message": "Welcome to My FastAPI App"}if __name__ == "__main__":import uvicornuvicorn.run(app, host="0.0.0.0", port=8000)
讲解:
- 导入库: 引入
FastAPI
和路由模块user
、item
。 - 创建应用:
app = FastAPI(...)
创建 FastAPI 应用实例,设定标题和版本。 - 挂载路由
app.include_router(...)
将用户和项目路由挂载到应用上,设置前缀和标签以便分类。
- 根路由
@app.get("/")
定义根路由,访问时返回一个欢迎消息。
- 运行应用: 使用
uvicorn.run(...)
启动应用,监听所有 IP 地址 (0.0.0.0
) 和 8000 端口。
2. routers/user.py
from fastapi import APIRouter, Body
from typing import Listrouter = APIRouter()fake_users_db = []@router.get("/", response_model=List[dict], summary="Get all users")
async def get_users():return fake_users_db@router.post("/", response_model=dict, summary="Create a new user")
async def create_user(user: dict = Body(...)):fake_users_db.append(user)return {"message": "User created", "user": user}@router.get("/{user_id}", summary="Get a specific user")
async def read_user(user_id: int):if user_id < len(fake_users_db):return fake_users_db[user_id]return {"error": "User not found"}
讲解:
- 路由器实例:
router = APIRouter()
创建一个路由器实例。 - 模拟数据库:
fake_users_db
是一个列表,用于存储用户数据。 - 获取所有用户
@router.get("/")
定义获取所有用户的 GET 请求。"/"
表示这个路由的路径是根路径。也就是说,访问/users/
(假设该路由挂载在/users
下)时,会触发这个函数。- 响应模型:
response_model=List[dict]
指定了该路由的响应体应该是一个字典列表。具体来说,返回的 JSON 数据格式应该是一个数组,其中每个元素都是一个字典。 - 类型提示: 使用类型提示可以帮助 FastAPI 自动生成 API 文档,并在请求时提供数据验证。这里表示返回的数据结构是一个包含字典的列表,字典的键值对可以根据具体实现自行定义。
- 摘要:
summary
参数是一个可选的描述,用于提供该路由的简短说明。在自动生成的 API 文档(如 Swagger UI)中,这个摘要会显示在相应的路由下,帮助用户快速理解该路由的功能。 - 返回
fake_users_db
列表。
- 创建新用户
@router.post("/")
定义创建新用户的 POST 请求。- 使用
Body(...)
解析请求体中的用户数据,并添加到fake_users_db
。
- 获取特定用户
@router.get("/{user_id}")
通过用户 ID 获取用户。- 检查用户 ID 是否有效,若有效返回用户数据,否则返回错误消息。
3. routers/item.py
from fastapi import APIRouter, Body
from typing import Listrouter = APIRouter()fake_items_db = []@router.get("/", response_model=List[dict], summary="Get all items")
async def get_items():return fake_items_db@router.post("/", response_model=dict, summary="Create a new item")
async def create_item(item: dict = Body(...)):fake_items_db.append(item)return {"message": "Item created", "item": item}@router.get("/{item_id}", summary="Get a specific item")
async def read_item(item_id: int):if item_id < len(fake_items_db):return fake_items_db[item_id]return {"error": "Item not found"}
讲解:
- 路由器实例: 同样使用
APIRouter()
创建路由器。 - 模拟数据库:
fake_items_db
用于存储项目数据。 - 获取所有项目
@router.get("/")
定义获取所有项目的 GET 请求,返回fake_items_db
列表。
- 创建新项目
@router.post("/")
定义创建新项目的 POST 请求,使用Body(...)
解析请求体。
- 获取特定项目
@router.get("/{item_id}")
通过项目 ID 获取项目数据,检查有效性。
4. requirements.txt
fastapi
uvicorn
说明:
- 目录结构: 项目分为主要应用 (
main.py
) 和路由模块 (routers/
),使得代码更易于维护。 - 路由:
user.py
: 定义用户相关的 API,包括获取用户、创建用户和获取特定用户。item.py
: 定义项目相关的 API,功能与用户类似。
- 挂载路由: 在
main.py
中,使用include_router
将用户和项目路由挂载到主应用上,定义了前缀/users
和/items
。 - 运行: 使用
uvicorn
启动应用,访问http://localhost:8000/docs
查看 API 文档。
如何运行:
-
创建一个名为
my_fastapi_app
的文件夹,并在其中创建上述文件和文件夹。 -
在终端中,导航到该文件夹,并运行以下命令安装依赖项:
pip install -r requirements.txt
-
然后,运行应用:
python main.py
希望这个示例能帮助您理解 FastAPI 的基本用法!如果有任何问题,请随时问我。
chatchat的api.py
import nltk
import sys
import ossys.path.append(os.path.dirname(os.path.dirname(__file__)))from configs import VERSION
from configs.model_config import NLTK_DATA_PATH
from configs.server_config import OPEN_CROSS_DOMAIN
import argparse
import uvicorn
from fastapi import Body
from fastapi.middleware.cors import CORSMiddleware
from starlette.responses import RedirectResponse
from server.chat.chat import chat
from server.chat.search_engine_chat import search_engine_chat
from server.chat.completion import completion
from server.chat.feedback import chat_feedback
from server.embeddings_api import embed_texts_endpoint
from server.llm_api import (list_running_models, list_config_models,change_llm_model, stop_llm_model,get_model_config, list_search_engines)
from server.utils import (BaseResponse, ListResponse, FastAPI, MakeFastAPIOffline,get_server_configs, get_prompt_template)
from typing import List, Literalnltk.data.path = [NLTK_DATA_PATH] + nltk.data.pathasync def document():return RedirectResponse(url="/docs")def create_app(run_mode: str = None):app = FastAPI(title="Langchain-Chatchat API Server",version=VERSION)MakeFastAPIOffline(app)# Add CORS middleware to allow all origins# 在config.py中设置OPEN_DOMAIN=True,允许跨域# set OPEN_DOMAIN=True in config.py to allow cross-domainif OPEN_CROSS_DOMAIN:app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],)mount_app_routes(app, run_mode=run_mode)return appdef mount_app_routes(app: FastAPI, run_mode: str = None):app.get("/",response_model=BaseResponse,summary="swagger 文档")(document)# Tag: Chatapp.post("/chat/chat",tags=["Chat"],summary="与llm模型对话(通过LLMChain)",)(chat)app.post("/chat/search_engine_chat",tags=["Chat"],summary="与搜索引擎对话",)(search_engine_chat)app.post("/chat/feedback",tags=["Chat"],summary="返回llm模型对话评分",)(chat_feedback)# 知识库相关接口mount_knowledge_routes(app)# 摘要相关接口mount_filename_summary_routes(app)# LLM模型相关接口app.post("/llm_model/list_running_models",tags=["LLM Model Management"],summary="列出当前已加载的模型",)(list_running_models)app.post("/llm_model/list_config_models",tags=["LLM Model Management"],summary="列出configs已配置的模型",)(list_config_models)app.post("/llm_model/get_model_config",tags=["LLM Model Management"],summary="获取模型配置(合并后)",)(get_model_config)app.post("/llm_model/stop",tags=["LLM Model Management"],summary="停止指定的LLM模型(Model Worker)",)(stop_llm_model)app.post("/llm_model/change",tags=["LLM Model Management"],summary="切换指定的LLM模型(Model Worker)",)(change_llm_model)# 服务器相关接口app.post("/server/configs",tags=["Server State"],summary="获取服务器原始配置信息",)(get_server_configs)app.post("/server/list_search_engines",tags=["Server State"],summary="获取服务器支持的搜索引擎",)(list_search_engines)@app.post("/server/get_prompt_template",tags=["Server State"],summary="获取服务区配置的 prompt 模板")def get_server_prompt_template(type: Literal["llm_chat", "knowledge_base_chat", "search_engine_chat", "agent_chat"]=Body("llm_chat", description="模板类型,可选值:llm_chat,knowledge_base_chat,search_engine_chat,agent_chat"),name: str = Body("default", description="模板名称"),) -> str:return get_prompt_template(type=type, name=name)# 其它接口app.post("/other/completion",tags=["Other"],summary="要求llm模型补全(通过LLMChain)",)(completion)app.post("/other/embed_texts",tags=["Other"],summary="将文本向量化,支持本地模型和在线模型",)(embed_texts_endpoint)def mount_knowledge_routes(app: FastAPI):from server.chat.knowledge_base_chat import knowledge_base_chatfrom server.chat.file_chat import upload_temp_docs, file_chatfrom server.chat.agent_chat import agent_chatfrom server.knowledge_base.kb_api import list_kbs, create_kb, delete_kbfrom server.knowledge_base.kb_doc_api import (list_files, upload_docs, delete_docs,update_docs, download_doc, recreate_vector_store,search_docs, DocumentWithVSId, update_info,update_docs_by_id,)app.post("/chat/knowledge_base_chat",tags=["Chat"],summary="与知识库对话")(knowledge_base_chat)app.post("/chat/file_chat",tags=["Knowledge Base Management"],summary="文件对话")(file_chat)app.post("/chat/agent_chat",tags=["Chat"],summary="与agent对话")(agent_chat)# Tag: Knowledge Base Managementapp.get("/knowledge_base/list_knowledge_bases",tags=["Knowledge Base Management"],response_model=ListResponse,summary="获取知识库列表")(list_kbs)app.post("/knowledge_base/create_knowledge_base",tags=["Knowledge Base Management"],response_model=BaseResponse,summary="创建知识库")(create_kb)app.post("/knowledge_base/delete_knowledge_base",tags=["Knowledge Base Management"],response_model=BaseResponse,summary="删除知识库")(delete_kb)app.get("/knowledge_base/list_files",tags=["Knowledge Base Management"],response_model=ListResponse,summary="获取知识库内的文件列表")(list_files)app.post("/knowledge_base/search_docs",tags=["Knowledge Base Management"],response_model=List[DocumentWithVSId],summary="搜索知识库")(search_docs)app.post("/knowledge_base/update_docs_by_id",tags=["Knowledge Base Management"],response_model=BaseResponse,summary="直接更新知识库文档")(update_docs_by_id)app.post("/knowledge_base/upload_docs",tags=["Knowledge Base Management"],response_model=BaseResponse,summary="上传文件到知识库,并/或进行向量化")(upload_docs)app.post("/knowledge_base/delete_docs",tags=["Knowledge Base Management"],response_model=BaseResponse,summary="删除知识库内指定文件")(delete_docs)app.post("/knowledge_base/update_info",tags=["Knowledge Base Management"],response_model=BaseResponse,summary="更新知识库介绍")(update_info)app.post("/knowledge_base/update_docs",tags=["Knowledge Base Management"],response_model=BaseResponse,summary="更新现有文件到知识库")(update_docs)app.get("/knowledge_base/download_doc",tags=["Knowledge Base Management"],summary="下载对应的知识文件")(download_doc)app.post("/knowledge_base/recreate_vector_store",tags=["Knowledge Base Management"],summary="根据content中文档重建向量库,流式输出处理进度。")(recreate_vector_store)app.post("/knowledge_base/upload_temp_docs",tags=["Knowledge Base Management"],summary="上传文件到临时目录,用于文件对话。")(upload_temp_docs)def mount_filename_summary_routes(app: FastAPI):from server.knowledge_base.kb_summary_api import (summary_file_to_vector_store, recreate_summary_vector_store,summary_doc_ids_to_vector_store)app.post("/knowledge_base/kb_summary_api/summary_file_to_vector_store",tags=["Knowledge kb_summary_api Management"],summary="单个知识库根据文件名称摘要")(summary_file_to_vector_store)app.post("/knowledge_base/kb_summary_api/summary_doc_ids_to_vector_store",tags=["Knowledge kb_summary_api Management"],summary="单个知识库根据doc_ids摘要",response_model=BaseResponse,)(summary_doc_ids_to_vector_store)app.post("/knowledge_base/kb_summary_api/recreate_summary_vector_store",tags=["Knowledge kb_summary_api Management"],summary="重建单个知识库文件摘要")(recreate_summary_vector_store)def run_api(host, port, **kwargs):if kwargs.get("ssl_keyfile") and kwargs.get("ssl_certfile"):uvicorn.run(app,host=host,port=port,ssl_keyfile=kwargs.get("ssl_keyfile"),ssl_certfile=kwargs.get("ssl_certfile"),)else:uvicorn.run(app, host=host, port=port)if __name__ == "__main__":parser = argparse.ArgumentParser(prog='langchain-ChatGLM',description='About langchain-ChatGLM, local knowledge based ChatGLM with langchain'' | 基于本地知识库的 ChatGLM 问答')parser.add_argument("--host", type=str, default="0.0.0.0")parser.add_argument("--port", type=int, default=7861)parser.add_argument("--ssl_keyfile", type=str)parser.add_argument("--ssl_certfile", type=str)# 初始化消息args = parser.parse_args()args_dict = vars(args)app = create_app()run_api(host=args.host,port=args.port,ssl_keyfile=args.ssl_keyfile,ssl_certfile=args.ssl_certfile,)
这段代码是一个 FastAPI 应用的完整实现,包含了聊天、知识库管理和模型管理等功能。以下是对代码各部分的详细讲解:
1. 导入模块
import nltk
import sys
import os
import argparse
import uvicorn
from fastapi import Body
from fastapi.middleware.cors import CORSMiddleware
from starlette.responses import RedirectResponse
from server.chat.chat import chat
from server.chat.search_engine_chat import search_engine_chat
# ... 省略其他导入
- nltk: 用于自然语言处理。
- sys和os: 用于系统路径管理。
- argparse: 用于解析命令行参数。
- uvicorn: 用于运行 FastAPI 应用的 ASGI 服务器。
- FastAPI 和相关模块: 提供构建 web 应用的功能。
- 从其他模块导入的函数: 这些函数实现了具体的业务逻辑。
2. 设置 NLTK 数据路径
nltk.data.path = [NLTK_DATA_PATH] + nltk.data.path
- 将 NLTK 数据的路径添加到 NLTK 的数据搜索路径中,确保应用能找到所需的 NLP 数据。
3. 创建 FastAPI 应用
def create_app(run_mode: str = None):app = FastAPI(title="Langchain-Chatchat API Server",version=VERSION)MakeFastAPIOffline(app)
- create_app: 创建并配置一个 FastAPI 应用实例。
- 标题和版本: 设置应用的标题和版本信息。
- MakeFastAPIOffline: 可能用于将 FastAPI 应用配置为离线模式(具体实现需查看该函数的定义)。
4. CORS 中间件
if OPEN_CROSS_DOMAIN:app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],)
- CORS 中间件: 允许跨域请求。
OPEN_CROSS_DOMAIN
变量决定是否启用跨域功能。 - 设置: 允许所有来源、凭证、HTTP 方法和请求头。
5. 注册路由
mount_app_routes(app, run_mode=run_mode)
- 调用
mount_app_routes
函数,将多个路由注册到 FastAPI 应用中。
6. mount_app_routes 函数
此函数负责将各种路由挂载到 FastAPI 应用上:
-
根路由:
app.get("/", response_model=BaseResponse, summary="swagger 文档")(document)
- 指定根路径返回 Swagger 文档的重定向。
-
聊天相关路由:
app.post("/chat/chat", tags=["Chat"], summary="与llm模型对话(通过LLMChain)")(chat)
- 注册与 LLM 模型对话的路由,使用
chat
函数处理请求。
- 注册与 LLM 模型对话的路由,使用
-
知识库和模型管理路由: 包含创建、更新、删除知识库的功能,以及列出和管理 LLM 模型的接口。
7. 知识库和摘要相关接口
def mount_knowledge_routes(app: FastAPI):from server.chat.knowledge_base_chat import knowledge_base_chat# 省略导入...app.post("/knowledge_base/upload_docs", tags=["Knowledge Base Management"], response_model=BaseResponse, summary="上传文件到知识库,并/或进行向量化")(upload_docs)
- 该函数集中管理知识库相关的路由,包括文件上传、搜索和更新操作。
8. 启动 API
def run_api(host, port, **kwargs):if kwargs.get("ssl_keyfile") and kwargs.get("ssl_certfile"):uvicorn.run(app, host=host, port=port, ssl_keyfile=kwargs.get("ssl_keyfile"), ssl_certfile=kwargs.get("ssl_certfile"))else:uvicorn.run(app, host=host, port=port)
- run_api: 启动 FastAPI 应用,可以选择使用 SSL。
9. 主程序入口
if __name__ == "__main__":parser = argparse.ArgumentParser(prog='langchain-ChatGLM', description='About langchain-ChatGLM, local knowledge based ChatGLM with langchain')# 省略命令行参数解析app = create_app()run_api(host=args.host, port=args.port, ssl_keyfile=args.ssl_keyfile, ssl_certfile=args.ssl_certfile)
- 命令行参数: 允许用户通过命令行指定主机、端口及 SSL 证书。
- 创建和启动应用: 调用
create_app
函数创建 FastAPI 应用,并启动 API 服务。
总结
这段代码展示了一个功能全面的 FastAPI 应用框架,集成了聊天功能、知识库管理和模型控制。通过模块化设计,清晰地划分了不同的业务逻辑,并提供了丰富的接口供前端或其他服务调用。代码也展示了如何处理跨域请求、路由注册和命令行参数解析等常见的 web 应用开发任务。
Uvicorn
当然可以!Uvicorn 是 Python 生态系统中一个高性能的 ASGI(Asynchronous Server Gateway Interface)服务器,广泛用于运行异步Web框架,如 FastAPI 和 Starlette。作为一个刚开始 Python 后端开发的人员,理解 Uvicorn 的概念、功能、使用方法以及如何优化它,对于构建高效、可扩展的后端服务至关重要。以下是关于 Uvicorn 的全面讲解。
1. 什么是 Uvicorn?
Uvicorn 是一个基于 uvloop 和 httptools 的轻量级、快速的 ASGI 服务器。它专为运行异步应用程序而设计,能够充分利用 Python 的异步特性,实现高并发和低延迟的性能表现。
ASGI 简介
- WSGI(Web Server Gateway Interface):传统的 Python Web 服务器接口,支持同步请求处理。
- ASGI(Asynchronous Server Gateway Interface):现代的 Python Web 服务器接口,支持异步请求处理,能够处理长连接(如 WebSocket)和高并发。
Uvicorn 实现了 ASGI 规范,使其成为支持异步功能的现代 Web 框架(如 FastAPI)的理想选择。
2. Uvicorn 的主要特性
- 高性能:基于 uvloop(一个快速的事件循环)和 httptools(一个快速的 HTTP 解析库),提供卓越的性能表现。
- 异步支持:原生支持异步编程,适用于需要高并发和实时通信的应用。
- 轻量级:简洁的设计和低资源消耗,适合微服务和小型应用。
- 多协议支持:支持 HTTP/1.1、HTTP/2 和 WebSocket 协议。
- 易于集成:与 FastAPI、Starlette 等现代 Python Web 框架无缝集成。
- 热重载:开发模式下支持代码更改时自动重启,提升开发效率。
- 灵活的配置:提供多种启动参数和配置选项,满足不同的部署需求。
3. 安装 Uvicorn
使用 pip 安装
pip install uvicorn
安装特定版本
如果需要安装特定版本,可以指定版本号:
pip install uvicorn==0.20.0
安装额外依赖
Uvicorn 支持不同的工作模式和功能,您可以根据需要安装额外的依赖:
-
标准安装:
pip install uvicorn
-
安装全功能版本(包含 HTTP/2 和 WebSocket 支持):
pip install uvicorn[standard]
这将安装
uvloop
、httptools
、gunicorn
、python-dotenv
等额外依赖,提升性能和功能。
4. 基本使用
启动一个简单的 ASGI 应用
假设您有一个简单的 ASGI 应用 app.py
:
# app.py
from fastapi import FastAPIapp = FastAPI()@app.get("/")
async def read_root():return {"message": "Hello, Uvicorn!"}
使用 Uvicorn 启动应用
在命令行中运行以下命令:
uvicorn app:app --reload
app:app
:指的是app.py
文件中的app
对象。--reload
:启用热重载,开发阶段使用,代码更改时自动重启服务器。
访问应用
在浏览器中访问 http://127.0.0.1:8000,您将看到:
{"message": "Hello, Uvicorn!"
}
5. 主要命令行参数
Uvicorn 提供了丰富的命令行参数,用于控制服务器的行为。以下是一些常用参数:
参数 | 描述 | 默认值 |
---|---|---|
app | ASGI 应用路径(如 module:app ) | 必须指定 |
--host / -h | 服务器绑定的主机地址 | 127.0.0.1 |
--port / -p | 服务器绑定的端口号 | 8000 |
--reload | 启用自动重载(开发模式) | False |
--workers / -w | 工作进程数量(建议在生产环境中使用 Gunicorn 管理多个 Uvicorn 进程) | 1 |
--loop | 选择事件循环实现(auto 、asyncio 、uvloop ) | auto |
--http | 选择 HTTP 实现(auto 、httptools 、h11 ) | auto |
--ws | 选择 WebSocket 实现(auto 、websockets 、none ) | auto |
--log-level | 设置日志级别(critical 、error 、warning 、info 、debug ) | info |
--access-log | 启用访问日志 | True |
--proxy-headers | 启用代理头部支持(如 X-Forwarded-For ) | False |
--root-path | 设置应用的根路径,用于部署在子路径下的应用 | / |
--ssl-keyfile | SSL 密钥文件路径,启用 HTTPS(如 --ssl-keyfile=key.pem --ssl-certfile=cert.pem ) | None |
--ssl-certfile | SSL 证书文件路径,启用 HTTPS | None |
--timeout-keep-alive | 设置连接保持活动状态的超时时间(秒) | 5 |
示例:指定主机和端口
uvicorn app:app --host 0.0.0.0 --port 9000
这将启动服务器,监听所有可用IP地址的9000端口。
示例:启用 HTTPS
uvicorn app:app --ssl-keyfile=path/to/key.pem --ssl-certfile=path/to/cert.pem
这将在安全的 HTTPS 上运行服务器。
6. 集成 FastAPI 与 Uvicorn
FastAPI 是一个现代、快速(高性能)的 Web 框架,基于标准的 Python 类型提示,使用 Uvicorn 作为 ASGI 服务器可以充分发挥其性能优势。
创建一个 FastAPI 应用
# main.py
from fastapi import FastAPIapp = FastAPI()@app.get("/")
async def read_root():return {"message": "Hello, FastAPI with Uvicorn!"}
启动应用
uvicorn main:app --reload
访问文档
FastAPI 自动生成交互式 API 文档,访问:
- Swagger UI:http://127.0.0.1:8000/docs
- ReDoc:http://127.0.0.1:8000/redoc
7. 生产环境中的部署
虽然 Uvicorn 可以直接在生产环境中使用,但结合 Gunicorn 管理多个工作进程,可以进一步提升性能和可靠性。
安装 Gunicorn 和 Uvicorn Workers
pip install gunicorn
pip install uvicorn
使用 Gunicorn 启动 Uvicorn Workers
gunicorn app.main:app -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 --workers 4
-k uvicorn.workers.UvicornWorker
:指定 Gunicorn 使用 Uvicorn 的工作进程。--workers 4
:启动4个工作进程,根据服务器的 CPU 核心数进行调整。
使用配置文件
为了更好地管理 Gunicorn 配置,可以使用配置文件。例如,创建 gunicorn_conf.py
:
# gunicorn_conf.py
bind = "0.0.0.0:8000"
workers = 4
worker_class = "uvicorn.workers.UvicornWorker"
loglevel = "info"
然后启动 Gunicorn:
gunicorn app.main:app -c gunicorn_conf.py
使用 Process Manager
在生产环境中,推荐使用 Process Manager(如 systemd、supervisord、pm2)来管理 Gunicorn 进程,确保在服务器重启或应用崩溃时自动重启。
示例:使用 systemd 管理 Gunicorn
-
创建 systemd 服务文件
创建
/etc/systemd/system/gunicorn.service
:[Unit] Description=Gunicorn instance to serve Auto Build API After=network.target[Service] User=your_username Group=www-data WorkingDirectory=/path/to/your/project ExecStart=/path/to/your/venv/bin/gunicorn app.main:app -c gunicorn_conf.py[Install] WantedBy=multi-user.target
-
启动并启用服务
sudo systemctl start gunicorn sudo systemctl enable gunicorn
-
检查服务状态
sudo systemctl status gunicorn
8. Uvicorn 的高级功能与优化
8.1 热重载
在开发阶段,使用 --reload
参数可以自动重启服务器,方便快速迭代开发。
uvicorn app.main:app --reload
注意:不要在生产环境中使用 --reload
,因为它会增加服务器的开销。
8.2 SSL 支持
为了确保数据传输的安全性,可以启用 SSL,使用 --ssl-keyfile
和 --ssl-certfile
参数。
uvicorn app.main:app --host 0.0.0.0 --port 443 --ssl-keyfile=path/to/key.pem --ssl-certfile=path/to/cert.pem
注意:在生产环境中,通常建议使用反向代理(如 NGINX)来处理 SSL,而不是直接在 Uvicorn 上启用 SSL。
8.3 环境变量与配置
使用环境变量和配置文件管理应用配置,提升安全性和灵活性。
示例:使用 .env
文件
-
安装
python-dotenv
pip install python-dotenv
-
创建
.env
文件HOST=0.0.0.0 PORT=8000 LOG_LEVEL=info
-
加载环境变量
在
main.py
中:import os from dotenv import load_dotenv from fastapi import FastAPIload_dotenv() # 加载 .env 文件app = FastAPI()@app.get("/") async def read_root():return {"message": "Hello, Uvicorn with Env Variables!"}
-
使用环境变量启动 Uvicorn
uvicorn app.main:app --host $HOST --port $PORT --log-level $LOG_LEVEL
8.4 事件循环与并发
Uvicorn 使用异步编程模型,通过事件循环实现高并发处理。确保在编写应用程序时充分利用异步特性,避免阻塞操作。
示例:异步数据库操作
from fastapi import FastAPI
from databases import Databaseapp = FastAPI()
database = Database("sqlite:///test.db")@app.on_event("startup")
async def startup():await database.connect()@app.on_event("shutdown")
async def shutdown():await database.disconnect()@app.get("/users")
async def get_users():query = "SELECT * FROM users"results = await database.fetch_all(query)return results
8.5 中间件(Middleware)
使用中间件对请求和响应进行预处理和后处理,如日志记录、身份验证、跨域资源共享(CORS)等。
示例:添加 CORS 中间件
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddlewareapp = FastAPI()# 配置允许的来源
origins = ["http://localhost","http://localhost:3000",
]app.add_middleware(CORSMiddleware,allow_origins=origins,allow_credentials=True,allow_methods=["*"],allow_headers=["*"],
)@app.get("/")
async def read_root():return {"message": "Hello, Uvicorn with CORS!"}
8.6 性能监控与优化
使用 Gunicorn 的预热
Gunicorn 支持预热工作进程,减少启动延迟,提高响应速度。
gunicorn app.main:app -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 --workers 4 --preload
启用 HTTP/2
通过使用支持 HTTP/2 的服务器或代理(如 NGINX)来提升性能,尤其是在高延迟网络环境下。
负载均衡
在多台服务器之间分配请求,使用 NGINX、HAProxy 等工具实现负载均衡,提升应用的可扩展性和可靠性。
9. 常见问题与故障排除
9.1 连接无法建立
可能原因:
- Uvicorn 未启动或未正确绑定到指定的主机和端口。
- 防火墙或安全组阻止了连接。
- 服务器地址或端口错误。
解决方法:
- 确认 Uvicorn 是否正在运行,并监听正确的主机和端口。
- 检查防火墙设置,确保允许指定端口的流量。
- 使用
curl
或其他工具测试连接。
9.2 热重载不起作用
可能原因:
- 使用了不支持热重载的部署方式。
- 代码未保存,导致监控不到文件更改。
解决方法:
- 确保在开发环境中使用
--reload
参数启动 Uvicorn。 - 确保代码文件已保存,并且文件系统支持监控(部分虚拟文件系统可能不支持)。
9.3 性能低下
可能原因:
- 应用中存在阻塞操作,未充分利用异步特性。
- 工作进程数量不足,无法处理高并发请求。
- 资源(CPU、内存)不足。
解决方法:
- 确保所有 I/O 操作(如数据库、网络请求)使用异步库。
- 根据服务器的 CPU 核心数调整工作进程数量。
- 监控服务器资源使用情况,必要时升级硬件或优化代码。
9.4 SSL 证书错误
可能原因:
- SSL 密钥或证书文件路径错误。
- 证书格式不正确或损坏。
- 使用自签名证书时,客户端未信任证书。
解决方法:
- 确认密钥和证书文件路径正确。
- 检查证书文件的格式和完整性。
- 在开发阶段,可以使用自签名证书并在客户端信任。
10. 最佳实践与建议
10.1 使用虚拟环境
始终在虚拟环境中开发和运行项目,避免依赖冲突并确保项目可移植性。
python3 -m venv venv
source venv/bin/activate # Unix/macOS
# 或
venv\Scripts\activate # Windows
10.2 管理依赖
使用 requirements.txt
或 Pipfile
管理项目依赖,确保环境一致性。
# 生成 requirements.txt
pip freeze > requirements.txt# 安装依赖
pip install -r requirements.txt
10.3 日志记录
配置适当的日志记录,便于监控和调试。
import logging
from fastapi import FastAPIlogging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)app = FastAPI()@app.get("/")
async def read_root():logger.info("Root endpoint called")return {"message": "Hello, Uvicorn with Logging!"}
10.4 安全性
- 使用 HTTPS:确保数据传输的安全性。
- 认证与授权:保护 API 端点,确保只有授权用户可以访问。
- 输入验证:使用 Pydantic 模型验证输入数据,防止注入攻击等。
10.5 监控与报警
集成监控工具,如 Prometheus、Grafana,实时监控应用性能和健康状态,并设置报警机制。
10.6 编写测试
编写单元测试和集成测试,确保应用功能的正确性和稳定性。使用 pytest 等测试框架进行测试。
# test_app.py
from fastapi.testclient import TestClient
from app.main import appclient = TestClient(app)def test_read_root():response = client.get("/")assert response.status_code == 200assert response.json() == {"message": "Hello, Uvicorn!"}
运行测试:
pytest
10.7 文档与代码质量
- 自动生成文档:利用 FastAPI 的自动文档生成功能,提供详细的 API 文档。
- 代码格式化:使用工具如 Black、isort 统一代码格式。
- 代码静态检查:使用 flake8、mypy 等工具检查代码质量和类型错误。
10.8 持续集成与部署(CI/CD)
配置 CI/CD 流水线(如 GitHub Actions、GitLab CI),实现代码的自动测试、构建和部署,提高开发效率和代码质量。
示例:GitHub Actions 工作流
创建 .github/workflows/ci.yml
:
name: CIon:push:branches: [ main ]pull_request:branches: [ main ]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v2- name: Set up Pythonuses: actions/setup-python@v2with:python-version: '3.9'- name: Install dependenciesrun: |python -m pip install --upgrade pippip install -r requirements.txt- name: Lint with flake8run: |pip install flake8flake8 .- name: Test with pytestrun: |pip install pytestpytest
11. 示例项目:综合应用 Uvicorn 与 FastAPI
为了更好地理解 Uvicorn 的应用,以下是一个综合示例项目,涵盖基本的 API 创建、WebSocket 通信、日志记录和部署。
项目结构
auto_build_project/
├── app/
│ ├── __init__.py
│ ├── main.py
│ ├── routers/
│ │ ├── __init__.py
│ │ ├── http.py
│ │ └── websocket.py
│ ├── modules/
│ │ ├── __init__.py
│ │ ├── config_checker.py
│ │ ├── info_collector.py
│ │ ├── workflow_generator.py
│ │ ├── config_generator.py
│ │ ├── workflow_adjuster.py
│ │ └── workflow_debugger.py
│ └── schemas/
│ ├── __init__.py
│ ├── initiate.py
│ ├── workflow.py
│ ├── compile.py
│ ├── adjustment.py
│ └── debug.py
├── requirements.txt
├── README.md
└── .gitignore
1. app/main.py
from fastapi import FastAPI
from app.routers import http, websocketapp = FastAPI()app.include_router(http.router)
app.include_router(websocket.router)@app.get("/")
def read_root():return {"message": "Auto Build API is running."}
2. app/routers/websocket.py
实现 WebSocket 端点,包括 /auto_build/initiate
、/auto_build/workflow/adjustment
和 /auto_build/workflow/debug
。
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
from app.schemas.initiate import InitiateResponse
from app.schemas.adjustment import AdjustmentResponse
from app.schemas.debug import DebugStepResult
from app.modules.config_checker import check_configurations
from app.modules.info_collector import collect_information
from app.modules.workflow_adjuster import adjust_workflow
from app.modules.workflow_debugger import debug_workflow
import jsonrouter = APIRouter()@router.websocket("/auto_build/initiate")
async def initiate_build(websocket: WebSocket):await websocket.accept()try:while True:data = await websocket.receive_text()request = json.loads(data)user_id = request.get("user_id")autobuild_id = request.get("autobuild_id")user_input = request.get("user_input")print(f"Received build request from user_id={user_id}, autobuild_id={autobuild_id}")# 前置配置检查missing_configs = check_configurations()if missing_configs:response = InitiateResponse(status="failure",missing_configurations=missing_configs,message="配置检查未通过。")await websocket.send_text(json.dumps(response.dict()))continue # 继续等待下一个请求# 前置配置通过,进行信息收集collected_info = collect_information(user_input)response = {"status": "success","collected_info": collected_info,"message": "信息收集完毕,构建准备状态。"}await websocket.send_text(json.dumps(response))except WebSocketDisconnect:print(f"WebSocket连接断开: {websocket.client}")except Exception as e:print(f"发生错误: {e}")await websocket.close(code=1003)@router.websocket("/auto_build/workflow/adjustment")
async def adjust_workflow_ws(websocket: WebSocket):await websocket.accept()try:while True:data = await websocket.receive_text()request = json.loads(data)user_id = request.get("user_id")autobuild_id = request.get("autobuild_id")workflow = request.get("workflow")user_commands = request.get("user_commands", []) # 用户调整指令# 调整工作流adjusted_workflow = adjust_workflow(workflow, user_commands)response = {"status": "success","workflow": adjusted_workflow,"message": "工作流调整成功。"}await websocket.send_text(json.dumps(response))except WebSocketDisconnect:print(f"WebSocket连接断开: {websocket.client}")except Exception as e:print(f"发生错误: {e}")await websocket.close(code=1003)@router.websocket("/auto_build/workflow/debug")
async def debug_workflow_ws(websocket: WebSocket):await websocket.accept()try:data = await websocket.receive_text()request = json.loads(data)user_id = request.get("user_id")autobuild_id = request.get("autobuild_id")workflow = request.get("workflow")# 调试工作流async for step_result in debug_workflow(workflow):await websocket.send_text(json.dumps(step_result))await websocket.send_text(json.dumps({"status": "completed", "message": "工作流调试完成。"}))except WebSocketDisconnect:print(f"WebSocket连接断开: {websocket.client}")except Exception as e:print(f"发生错误: {e}")await websocket.close(code=1003)
3. app/routers/http.py
实现 HTTP 端点,包括 /auto_build/workflow
和 /auto_build/workflow/compile
。
from fastapi import APIRouter, HTTPException
from app.schemas.workflow import WorkflowRequest, WorkflowResponse
from app.schemas.compile import CompileRequest, CompileResponse
from app.modules.workflow_generator import generate_workflow
from app.modules.config_generator import generate_configrouter = APIRouter()@router.post("/auto_build/workflow", response_model=WorkflowResponse)
def create_workflow(request: WorkflowRequest):try:workflow = generate_workflow(request.collected_info)return WorkflowResponse(status="success",workflow=workflow,message="工作流生成成功。")except Exception as e:raise HTTPException(status_code=500, detail=str(e))@router.post("/auto_build/workflow/compile", response_model=CompileResponse)
def compile_workflow(request: CompileRequest):try:compiled_workflow = generate_config(request.workflow)return CompileResponse(status="success",workflow=compiled_workflow,message="工作流配置补全成功。")except Exception as e:raise HTTPException(status_code=500, detail=str(e))
4. 其他模块实现
根据需求,实现各个模块的功能。
4.1 app/modules/config_checker.py
def check_configurations():missing = []# 检查大模型配置是否存在model_config_exists = False # 实际检查逻辑if not model_config_exists:missing.append("大模型配置不存在")# 检查必要的资源和服务是否可用resources_available = False # 实际检查逻辑if not resources_available:missing.append("必要的资源和服务不可用")return missing
4.2 app/modules/info_collector.py
def collect_information(user_input):# 根据 user_input 收集必要的信息app_name = user_input.get("app_name")app_function = user_input.get("app_function")collected_info = {"app_name": app_name,"app_function": app_function}return collected_info
4.3 app/modules/workflow_generator.py
def match_template(collected_info):# 假设有预定义的模板templates = {"Data Processing": {"steps": ["fetch_data", "process_data", "store_results"]},"Machine Learning": {"steps": ["data_preprocessing", "train_model", "evaluate_model"]}}app_function = collected_info.get("app_function")if app_function in templates:return templates[app_function]return Nonedef generate_workflow(collected_info):template = match_template(collected_info)if template:# 使用模板生成工作流workflow = {"autobuild_id": collected_info.get("autobuild_id"),"steps": template["steps"]}else:# 模板匹配失败,生成自定义工作流workflow = {"autobuild_id": collected_info.get("autobuild_id"),"steps": ["custom_step1", "custom_step2"]}return workflow
4.4 app/modules/config_generator.py
def generate_config(workflow):# 检查每个步骤是否有配置信息,若无则补全for step in workflow.get("steps", []):if isinstance(step, dict) and "config" not in step:step["config"] = {"default_param": "value"} # 补全配置return workflow
4.5 app/modules/workflow_adjuster.py
def adjust_workflow(workflow, user_commands):# 根据 user_commands 调整工作流for command in user_commands:action = command.get("action")step = command.get("step")if action == "add":workflow["steps"].append(step)elif action == "delete":workflow["steps"] = [s for s in workflow["steps"] if s["name"] != step["name"]]elif action == "modify":for s in workflow["steps"]:if s["name"] == step["name"]:s.update(step.get("changes", {}))return workflow
4.6 app/modules/workflow_debugger.py
import asynciodef execute_step(step):# 模拟步骤执行,实际应包含具体逻辑if step["name"] == "fetch_data":return {"step": "fetch_data", "status": "success", "message": "数据获取成功。"}elif step["name"] == "process_data":return {"step": "process_data", "status": "success", "message": "数据处理成功。"}elif step["name"] == "validate_data":return {"step": "validate_data", "status": "failure", "message": "数据验证失败。"}else:return {"step": step["name"], "status": "success", "message": "步骤执行成功。"}async def debug_workflow(workflow):for step in workflow.get("steps", []):# 模拟执行时间await asyncio.sleep(1)result = execute_step(step)yield result
5. app/schemas/
使用 Pydantic 定义请求和响应的模型,确保数据验证和类型检查。
5.1 app/schemas/initiate.py
from pydantic import BaseModel
from typing import Listclass InitiateRequest(BaseModel):user_id: strautobuild_id: struser_input: dictclass InitiateResponse(BaseModel):status: strmissing_configurations: List[str] = []message: str = ""
5.2 app/schemas/workflow.py
from pydantic import BaseModelclass WorkflowRequest(BaseModel):user_id: strautobuild_id: strcollected_info: dictclass WorkflowResponse(BaseModel):status: strworkflow: dict = {}message: str = ""
5.3 app/schemas/compile.py
from pydantic import BaseModelclass CompileRequest(BaseModel):user_id: strautobuild_id: strworkflow: dictclass CompileResponse(BaseModel):status: strworkflow: dict = {}message: str = ""
5.4 app/schemas/adjustment.py
from pydantic import BaseModelclass AdjustmentRequest(BaseModel):user_id: strautobuild_id: strworkflow: dictuser_commands: list = []class AdjustmentResponse(BaseModel):status: strworkflow: dict = {}message: str = ""
5.5 app/schemas/debug.py
from pydantic import BaseModelclass DebugRequest(BaseModel):user_id: strautobuild_id: strworkflow: dictclass DebugStepResult(BaseModel):step: strstatus: strmessage: str = ""
6. 运行和测试项目
6.1 启动服务器
在项目根目录下运行以下命令:
uvicorn app.main:app --reload
6.2 测试 HTTP 端点
使用 Postman 或 cURL 发送 POST 请求到 /auto_build/workflow
和 /auto_build/workflow/compile
。
示例:生成工作流
curl -X POST "http://127.0.0.1:8000/auto_build/workflow" \
-H "Content-Type: application/json" \
-d '{"user_id": "user123","autobuild_id": "build456","collected_info": {"app_name": "MyApp","app_function": "Data Processing"}
}'
预期响应:
{"status": "success","workflow": {"autobuild_id": "build456","steps": ["fetch_data", "process_data", "store_results"]},"message": "工作流生成成功。"
}
示例:补全配置
curl -X POST "http://127.0.0.1:8000/auto_build/workflow/compile" \
-H "Content-Type: application/json" \
-d '{"user_id": "user123","autobuild_id": "build456","workflow": {"autobuild_id": "build456","steps": [{"name": "fetch_data"},{"name": "process_data"},{"name": "store_results"}]}
}'
预期响应:
{"status": "success","workflow": {"autobuild_id": "build456","steps": [{"name": "fetch_data", "config": {"default_param": "value"}},{"name": "process_data", "config": {"default_param": "value"}},{"name": "store_results", "config": {"default_param": "value"}}]},"message": "工作流配置补全成功。"
}
6.3 测试 WebSocket 端点
使用浏览器控制台或 WebSocket 客户端工具发送构建请求和调整请求。
示例:使用浏览器控制台
- 打开浏览器,访问 http://127.0.0.1:8000。
- 打开开发者工具(通常按
F12
),切换到“Console”标签。 - 输入以下 JavaScript 代码:
// 创建 WebSocket 连接到 initiate 端点
const ws_initiate = new WebSocket("ws://127.0.0.1:8000/auto_build/initiate");ws_initiate.onopen = () => {console.log("WebSocket (initiate) 连接已打开");const request = {user_id: "user123",autobuild_id: "build456",user_input: {app_name: "MyApp",app_function: "Data Processing"}};ws_initiate.send(JSON.stringify(request));
};ws_initiate.onmessage = (event) => {const response = JSON.parse(event.data);console.log("收到 initiate 响应:", response);
};ws_initiate.onerror = (error) => {console.error("WebSocket (initiate) 错误:", error);
};ws_initiate.onclose = () => {console.log("WebSocket (initiate) 连接已关闭");
};// 创建 WebSocket 连接到 debug 端点
const ws_debug = new WebSocket("ws://127.0.0.1:8000/auto_build/workflow/debug");ws_debug.onopen = () => {console.log("WebSocket (debug) 连接已打开");const request = {user_id: "user123",autobuild_id: "build456",workflow: {"autobuild_id": "build456","steps": [{"name": "fetch_data"},{"name": "process_data"},{"name": "validate_data"}]}};ws_debug.send(JSON.stringify(request));
};ws_debug.onmessage = (event) => {const response = JSON.parse(event.data);console.log("收到 debug 响应:", response);
};ws_debug.onerror = (error) => {console.error("WebSocket (debug) 错误:", error);
};ws_debug.onclose = () => {console.log("WebSocket (debug) 连接已关闭");
};
预期输出:
-
Initiate 端点:
-
如果
config_checker
返回缺少配置:
{"status": "failure","missing_configurations": ["大模型配置不存在", "必要的资源和服务不可用"],"message": "配置检查未通过。" }
-
如果配置检查通过:
{"status": "success","collected_info": {"app_name": "MyApp","app_function": "Data Processing"},"message": "信息收集完毕,构建准备状态。" }
-
-
Debug 端点:
-
分步骤返回调试结果:
{"step": "fetch_data","status": "success","message": "数据获取成功。" } {"step": "process_data","status": "success","message": "数据处理成功。" } {"step": "validate_data","status": "failure","message": "数据验证失败。" } {"status": "completed","message": "工作流调试完成。" }
-
12. 性能优化与调优
12.1 使用 uvloop
提升性能
uvloop
是一个基于 libuv 的高性能事件循环,能够显著提升异步应用的性能。Uvicorn 默认在支持的平台上使用 uvloop
。
安装 uvloop
pip install uvloop
确认使用 uvloop
在 Uvicorn 启动日志中,您可以看到事件循环的实现。例如:
INFO: Started server process [12345]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
12.2 使用 httptools
提升 HTTP 解析速度
httptools
是一个快速的 HTTP 解析库,Uvicorn 使用它来处理 HTTP 请求。它提供了比纯 Python 实现更高的性能。
安装 httptools
pip install httptools
确认使用 httptools
默认情况下,Uvicorn 会自动检测并使用 httptools
,除非通过 --http
参数指定其他实现。
12.3 合理配置工作进程和线程
根据服务器的硬件资源和应用的需求,合理配置 Uvicorn 的工作进程和线程数量。
- 工作进程数量:通常与服务器的 CPU 核心数相匹配。例如,4 核 CPU 建议使用 4 个工作进程。
- 线程数量:默认使用单线程工作进程,适合 I/O 密集型应用。对于计算密集型任务,可以增加线程数量,但需要谨慎。
12.4 使用缓存
使用缓存技术(如 Redis、Memcached)减少重复计算和数据库访问,提升应用性能。
12.5 数据库优化
- 使用异步数据库驱动:如
Databases
、SQLModel
、Tortoise-ORM
等,充分利用异步特性。 - 优化查询:确保数据库查询高效,使用索引和优化查询语句。
12.6 静态文件处理
对于静态文件(如图片、CSS、JavaScript),推荐使用专门的静态文件服务器(如 NGINX)处理,减轻 Uvicorn 的负担。
13. 安全性考虑
13.1 使用 HTTPS
在生产环境中,确保所有通信使用 HTTPS,保护数据的机密性和完整性。
推荐做法:使用反向代理服务器(如 NGINX、HAProxy)处理 SSL,转发请求到 Uvicorn。
13.2 认证与授权
保护 API 端点,确保只有授权用户可以访问。常见的认证方式包括:
- JWT(JSON Web Tokens)
- OAuth2
- API Key
示例:使用 FastAPI 的 OAuth2
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearerapp = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")def fake_decode_token(token):return {"sub": "user123"}async def get_current_user(token: str = Depends(oauth2_scheme)):user = fake_decode_token(token)if not user:raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="无效的认证凭证",headers={"WWW-Authenticate": "Bearer"},)return user@app.get("/protected")
async def protected_route(current_user: dict = Depends(get_current_user)):return {"message": f"Hello, {current_user['sub']}!"}
13.3 输入验证
使用 Pydantic 模型验证所有输入数据,防止恶意数据和注入攻击。
from pydantic import BaseModel, Fieldclass UserInput(BaseModel):app_name: str = Field(..., min_length=1)app_function: str = Field(..., min_length=1)@app.post("/submit")
async def submit(input: UserInput):return {"message": f"Received {input.app_name} with function {input.app_function}"}
13.4 防止跨站请求伪造(CSRF)
对于需要保护的端点,实施 CSRF 保护机制,尤其是涉及状态更改的操作。
14. 实践中的建议
14.1 持续学习与实践
- 官方文档:深入阅读 Uvicorn 官方文档 和 FastAPI 官方文档。
- 开源项目:参与开源项目,学习实际应用中的 Uvicorn 和 FastAPI 使用方式。
- 社区支持:加入相关社区和论坛,如 Stack Overflow、Reddit 的 r/FastAPI 等,获取帮助和交流经验。
14.2 编写清晰的代码与文档
- 代码风格:遵循 PEP 8 代码规范,保持代码整洁和可读。
- 注释与文档:为复杂的逻辑添加注释,使用 docstring 记录函数和类的用途。
- 自动化文档:利用 FastAPI 的自动文档生成功能,保持 API 文档的最新和准确。
14.3 自动化测试
编写单元测试和集成测试,确保应用功能的正确性和稳定性。使用工具如 pytest 和 TestClient 进行测试。
# test_main.py
from fastapi.testclient import TestClient
from app.main import appclient = TestClient(app)def test_read_root():response = client.get("/")assert response.status_code == 200assert response.json() == {"message": "Auto Build API is running."}
14.4 性能监控与优化
集成性能监控工具,如 Prometheus、Grafana,实时监控应用的性能指标,并根据监控数据进行优化。
14.5 持续集成与部署(CI/CD)
配置 CI/CD 流水线,实现代码的自动化测试、构建和部署,提高开发效率和代码质量。
15. 总结
Uvicorn 是一个强大且高性能的 ASGI 服务器,适用于现代异步 Python Web 框架(如 FastAPI)的部署。通过理解其工作原理、配置选项和最佳实践,您可以构建高效、可扩展且安全的后端服务。以下是关键点的回顾:
- Uvicorn 介绍:
- 高性能的 ASGI 服务器,基于 uvloop 和 httptools。
- 支持异步编程和多协议通信。
- 安装与基本使用:
- 使用 pip 安装。
- 快速启动 ASGI 应用,并通过命令行参数进行配置。
- 集成 FastAPI:
- 无缝与 FastAPI 集成,充分利用其性能和功能优势。
- 自动生成 API 文档,简化开发流程。
- 生产环境部署:
- 结合 Gunicorn 管理多个 Uvicorn 工作进程,提升性能和可靠性。
- 使用反向代理服务器(如 NGINX)处理 SSL 和负载均衡。
- 高级功能与优化:
- 使用异步编程和优化事件循环,提升性能。
- 配置日志记录、监控和安全机制,确保应用的稳定性和安全性。
- 最佳实践:
- 采用虚拟环境和依赖管理,保持项目的可移植性。
- 编写清晰、可维护的代码,进行充分的测试。
- 持续学习和实践,跟进行业最佳实践和新技术。
通过系统学习和实践这些内容,您将能够充分利用 Uvicorn 的强大功能,构建高效、可靠的 Python 后端服务。如果在开发过程中遇到任何具体问题或需要进一步的示例,欢迎随时提问!
相关文章:
fastapi入门
好的,我将为您生成一个更详细、易于理解的 FastAPI 入门学习文档,特别是对复杂概念(如依赖注入)进行深入解释,帮助您在没有太多基础的情况下也能顺利学习和掌握 FastAPI。 FastAPI 入门学习文档 目录 简介环境搭建 2…...
RabbitMQ 之 死信队列
一、死信的概念 先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理 解,一般来说,producer 将消息投递到 broker 或者直接到 queue 里了,consumer 从 queue 取出消息进行…...
Android-如何实现Apng动画播放
01 Apng是什么 Apng(Animated Portable Network Graphics)顾名思义是基于 PNG 格式扩展的一种动画格式,增加了对动画图像的支持,同时加入了 24 位图像和8位 Alpha 透明度的支持,并且向下兼容 PNG。 Google封面图 02 A…...
微服务系统架构图
微服务架构是一种将单一应用程序开发为一组小型服务的架构风格。每个服务都在自己的进程中运行,它们之间采用轻量级的通信机制(如 HTTP/REST 或消息队列)进行相互协作。以下是关于微服务系统架构的简要介绍:一、核心特点独立部署 …...
04 —— Webpack打包CSS代码
加载器css-loader :解析css代码 webpack 中文文档 | webpack中文文档 | webpack中文网 加载器style-loader:把解析后的css代码插入到DOM style-loader | webpack 中文文档 | webpack中文文档 | webpack中文网 准备css代码,放到src/login目…...
【数据结构专栏】二叉搜索树(Binary Search Tree)的剖析?
文章目录 🧨前言1、二叉搜索树的基本概念?2、二叉搜索树的节点结构组成?3、二叉搜索树的插入操作?4、二叉搜索树的删除操作?5、二叉搜索树的遍历? 6、二叉搜索树的性能分析? 🎉完整代…...
SSM全家桶 1.Maven
或许总要彻彻底底地绝望一次 才能重新再活一次 —— 24.11.20 maven在如今的idea中已经实现自动配置,不需要我们手动下载 一、Maven的简介和快速入门 Maven 是一款为 Java 项目构建管理、依赖管理的工具(软件),使用 Maven 可以自动化构建测试、打包和发…...
前端三剑客(二):CSS
目录 1. CSS 基础 1.1 什么是 CSS 1.2 语法格式 1.3 引入方式 1.3.1 行内样式 1.3.2 内部样式 1.3.3 外部样式 1.4 CSS 编码规范 2. 选择器 2.1 标签选择器 2.2 id 选择器 2.3 class 选择器(类选择器) 2.4 复合选择器 2.5 通配符选择器 3. 常用 CSS 样式 3.1 c…...
解析html将表格插入word文档
用到依赖包 <dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.15.2</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweav…...
Java核心知识详解:String类、StringBuffer、数组及日期时间的全面解析
🚀 作者 :“码上有前” 🚀 文章简介 :Java 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 标题 Java核心知识详解:String类、StringBuffer、数组及日期时间的全面解析 摘要 在Java中…...
唯一设备序列号(UID)、唯一产品识别码(UPI)和备份寄存器BKP
文章目录 一、唯一设备序列号UID二、唯一产品识别码UPI三、备份寄存器BKP 一、唯一设备序列号UID MCU 系列产品内置两个不同长度的唯一设备序列号,分别为 96 位的 UID(Unique device ID)和 128 位的UCID(Unique Customer ID),这两个设备序列号存放在闪存…...
Kafka - 消费者程序仅消费一半分区消息的问题
1. 问题描述 修改安全服务状态有时逻辑正常有时候逻辑不正常,排查incident服务的日志发现消息可以正常发送到 kafka topic ,但是incident-cron 服务有时候有拉取消息的日志有时候没有日志。 kafka 生产者可以将消息正常发送到 kafka topic ,…...
养老院管理系统+小程序项目需求分析文档
智慧综合养老服务平台是以业务为牵引、场景为驱动,围绕“老人”业务域,持续沉淀和打磨形成适应不同养老业务发展需要的业务能力,推动业务模式升级,为养老服务提供数字化解决方案,并依托实体站点与养老机构实现线上线下…...
K8s 下通过prometheus监控 nginx
k8s 下有两个版本的nginx ingress 分别是 ingress nginx 以及 nginx ingress Ingress-nginx 与 Nginx-ingress - LeoZhanggg - 博客园 这里我讨论的是 nginx ingress Nginx Ingress 使用Prometheus 导出数据 nginx ingress 本身支持通过支持这个提供prometheus 格式的…...
基于SpringBoot的京东绿谷旅游信息服务平台设计与实现(源码+定制+开发)
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...
使用Redis生成全局唯一id
为了生成一个符合要求的分布式全局ID,我们可以使用 StringRedisTemplate 来实现。这个ID由三部分组成: 符号位(1 bit):始终为0,表示正数。时间戳(31 bit):表示从某个起始…...
pytorch自定义算子导出onnx
文章目录 1、为什么要自定义算子?2、如何自定义算子3、自定义算子导出onnx4、example1、重写一个pytorch 自定义算子(实现自定义激活函数)2、现有算子上封装pytorch 自定义算子(实现动态放大超分辨率模型) 1、为什么要…...
从搭建uni-app+vue3工程开始
技术栈 uni-app、vue3、typescript、vite、sass、uview-plus、pinia、axios 一、项目搭建 1、创建以 typescript 开发的工程 npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project2、安装sass npm install -D sass// 安装sass-loader,注意需要版本10&…...
波点音乐自动点击
波点音乐 import uiautomator2 as u2 import time import sys import os# 动态点击时间,打印剩余时间 def dynamic_sleep(seconds):wait_time secondsfor i in range(wait_time):print(f"Waiting... {wait_time - i} seconds remaining")sys.stdout.flu…...
【一篇搞定配置】wget 下载与安装(Window)
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀各种软件安装与配置_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1.…...
2025年春招修订版《C/C++笔面试系列》(1) C语言经典笔面试题(上)
C语言是嵌入式开发的常用语言,也是主要语言,很多企业在招聘嵌入式软件工程师时,C语言的熟练程度是一个重要考察点。笔试也是以C语言为主,所以想要拿到面试机会,还得通过C语言笔试,本专题总结了各大企业C语言…...
【042C】基于51RFID门禁系统(LCD12864显示)【Proteus仿真+Keil程序+报告+原理图】
☆、设计硬件组成:51单片机最小系统RFID读卡器4*4矩阵键盘AT24C02存储芯片LCD12864液晶显示继电器蜂鸣器LED灯。 1、设计采用STC89C52、AT89C52、AT89S52作为主控芯片,采用LCD12864液晶显示屏实时显示门禁系统; 2、系统集成两种解锁方式&am…...
scratch二次开发:blockly工作区垃圾桶和进度条的隐藏和显示
大家好,我是小黄。 本期给大家介绍的内容是实现blockly工作区的垃圾桶和进度条的显示和隐藏实现。 本次基于的项目源码大家可以关注小黄回复垃圾桶自行获取。 一.垃圾桶的显示和实现。 在blockly中,我们进行块的删除的时候最常用的两种方法是…...
【STM32】MPU6050初始化常用寄存器说明及示例代码
一、MPU6050常用配置寄存器 1、电源管理寄存器1( PWR_MGMT_1 ) 此寄存器允许用户配置电源模式和时钟源。 DEVICE_RESET :用于控制复位的比特位。设置为1时复位 MPU6050,内部寄存器恢复为默认值,复位结束…...
LDR6020驱动的Type-C接口显示器解决方案
一、引言 随着科技的飞速发展,Type-C接口凭借其高速数据传输、强大的电力传输能力以及便捷的正反可插设计,正逐渐成为现代电子设备的主流接口标准。在显示器领域,Type-C接口的引入不仅简化了线缆连接,还为用户带来了更丰富的功能…...
Spring Boot + Android 实现登录功能
在移动互联网的今天,许多应用需要通过移动端实现与服务器的交互功能,其中登录是最常见且基础的一种功能。通过登录,用户可以获得独特的身份标识,从而访问特定的资源或服务。本篇博客将详细介绍如何使用 Spring Boot 和 Android 实…...
【通俗理解】边际化技巧在概率论中的应用——从公式到实例
【通俗理解】边际化技巧在概率论中的应用——从公式到实例 关键词提炼 #边际化技巧 #概率论 #联合概率 #条件概率 #积分计算 #概率分布 #贝叶斯推断 第一节:边际化技巧的类比与核心概念【尽可能通俗】 边际化技巧,就像是你在一个复杂的概率迷宫中&am…...
Chen_AdaMV-MoE_Adaptive_Multi-Task_Vision_Mixture-of-Experts 译文
摘要 稀疏激活的专家混合(MoE)正在成为多任务学习(MTL)的一个有前途的范例。 MoE 不是将多个任务的知识压缩到单个模型中,而是分离参数空间,仅利用给定任务类型及其输入的相关模型片段,从而提供…...
多线程下使用数据库 - 20241124
问题 并发性较低,每秒千次但是较高一致性,比如利用数据库中的数据进行判断是否执行某个操作 存在的问题是,如何只锁定判断相关的数据,而不影响数据库操作无关数据。脏读/不可重复读/幻读 解决方案 利用数据InnoDB引擎的LBCC和…...
GMAN解读(论文+代码)
一、注意力机制 注意力机制与传统的卷积神经网络不同的是,前者擅长捕获全局依赖和长程关系,权重会动态调整。而后者对于所有特征都使用同一个卷积核。关于更多注意力机制内容,详见: 注意力机制、自注意力机制、多头注意力机制、通…...
《文件操作》
一 . 文本文件和二进制文件 根据数据的组织形式,数据文件被分为了二进制文件和文本文件 数据在内存中是以二进制的形式存储,如果不加转换的输出到外存的文件中,就是二进制文件。 如果要求在外存上以ASCII 码的形式存储,则需要再存…...
【君正T31开发记录】8.了解rtsp协议及设计模式
前边搞定了驱动,先不着急直接上手撸应用层的代码,先了解一下大致要用到的东西。 设计PC端先用vlc rtsp暂时H264编码(vlc好像不支持h265,这个后边我试试)的视频流,先需要支持上rtsp server,了解rtsp协议是必…...
C++菜鸟教程 - 从入门到精通 第三节
上节课的题 上节课的题,大家都做出来了吗? 看一下这道题: 题目描述 N!1*2*...*N; 例5!1*2*3*4*5120. 编程求1!2!3!...N!. 输入 输入一行,只有一个整数n (1<n<10) 输出 输出只有一行(这意味着末尾有一个回车符号),包括1…...
原生JS和CSS,HTML实现开屏弹窗
开屏弹窗常应用于打开游戏,或者打开网站的时候,跳出来在正中间,来显示一些信息,并可以设置今日不再显示 CSS代码如下 <style>#box {width: 100vw;height: 100vh;background-color: rgba(0, 0, 0, 0.2);position: relative…...
微软发布Win11 24H2系统11月可选更新KB5046740!
系统之家11月22日报道,微软针对Win11 24H2系统推出2024年11月最新可选更新补丁KB5046740,更新后系统版本后升至26100.2454,此次更新后修复当应用程序以PDF和XLSX格式导出图表对象时停止响应、无法使用API查找旋转信息等问题。以下小编将给大家…...
【Rabbitmq篇】高级特性----TTL,死信队列,延迟队列
目录 一.TTL 1.设置消息的TTL 2.设置队列的TTL 3.俩者区别 二.死信队列 定义: 消息成为死信的原因: 1.消息被拒绝(basic.reject 或 basic.nack) 2.消息过期(TTL) 3.队列达到最大长度 编辑 …...
【Linux】gcc/g++使用
编译 我们知道,gcc只能编译C,g既能编译C,也能编译C。 由于两者的选项是相同的,这里我们使用gcc来说明。 这就是一个我们在linux中gcc编译一段代码后会自动生成一个a.out为名的可执行文件,然后我们./a.out,…...
IDEA2023 SpringBoot整合MyBatis(三)
一、数据库表 CREATE TABLE students (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,age INT,gender ENUM(Male, Female, Other),email VARCHAR(100) UNIQUE,phone_number VARCHAR(20),address VARCHAR(255),date_of_birth DATE,enrollment_date DATE,cours…...
Java网络编程 - cookiesession
cookie 之前学习了 Okhttp3 库可以调用API、抓取网页、下载文件。但是这些操作都是不要求登录的,如果 API、网页、文件等内容要求登录才能访问,就需要学习新的 cookie 相关的知识。 下面以豆瓣为例,使用 Java 程序读取“我的豆瓣”页面内容…...
100.【C语言】数据结构之二叉树的堆实现(顺序结构) 1
目录 1.顺序结构 2.示意图 编辑 从物理结构还原为逻辑结构的方法 3.父子节点编号的规律 4.顺序存储的前提条件 5.堆的简介 堆的定义 堆的两个重要性质 小根堆和大根堆 6.堆的插入 7.堆的实现及操作堆的函数 堆的结构体定义 堆初始化函数HeapInit 堆插入元素函…...
《Python基础》之循环结构
目录 简介 一、for循环 1、基本语法与作用 2、使用 range() 函数配合 for 循环 3、嵌套的for循环 二、while循环 1、基本语法与作用 2、while 循环嵌套 (1)、while循环与while循环嵌套 (2)、while循环与for循环嵌套 简介 …...
使用JDBC操作数据库
文章目录 使用JDBC操作数据库1. JDBC访问数据库步骤2. Statement与PreparedStatement区别3. JDBC的内容4. JDBC封装4.1 为什么进行JDBC封装4.2 实现JDBC封装4.3 什么是DAO4.4 配置数据库访问参数4.5 配置数据库连接池使用之JNDI的方式 5. 单例模式5.1 懒汉模式5.2 饿汉模式 使用…...
轻松解析 PDF 文档:深入了解 Python 的 pdfplumber 库
轻松解析 PDF 文档:深入了解 Python 的 pdfplumber 库 PDF 是一种常见的文件格式,广泛用于报告、文档、表单等领域。然而,如何高效解析 PDF 内容(尤其是文本和表格),一直是开发者面临的挑战。pdfplumber 是…...
实验五 时域采样与频域采样
时域采样理论的验证 【实例3-1】近似绘制x (n) R4n 在(0,2 π \pi π ) 上的幅频响应曲线( F T [ x ( n ) ] FT[x(n)] FT[x(n)] )。 x [1, 1, 1, 1]; N 64; xk fft(x, N); figure; subplot(2, 1, 1); stem(0:3, x, .); subplot(2, 1, 2); k 0:N-1; plot(2*k/N, abs(x…...
爬虫cookie反爬------加速乐(jsl)
加速乐 反爬虫技术:加速乐采用了包括OB混淆、动态加密算法和多层Cookie获取等高级反爬虫技术,确保整体校验的严密性。关键校验字段位于Cookie中的 __jsl_clearance_s,其验证过程通常涉及三次关键的请求,有效抵御恶意爬虫的侵扰。…...
设计模式——解释器模式
定义: 解释器模式是一种行为设计模式,它给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在这种模式中,通常会将一个复杂的表达式(如数学表达…...
sorted()函数
sorted(iterable, keyNone, reverseFalse)iterable: 需要排序的可迭代对象(如列表、元组、字符串等)。 key: 一个函数,用于从每个元素中提取排序的依据。如果未指定,默认直接比较元素本身。 reverse: 一个布尔值,Tru…...
动静态分析
静态分析 获取哈希值: 查壳: 导出函数: 获取资源信息: 通过发现dos头和pe头,来确定它是个可执行程序。 动态分析...
2024年信号处理与神经网络应用国际学术会议(SPNNA 2024)
重要信息 会议时间:2024年12月13-15日 会议地点:中国武汉 会议官网:www.spnna.org 会议简介 2024年信号处理与神经网络应用国际学术会议(SPNNA 2024)将于2024年12月13日至15日在中国武汉召开。本次会议旨在为全球研…...
winfrom快速自适应
在软件界面设计中,我们通常需要添加各种布局器和规则来实现界面布局,但对于不太熟练的工程师来说,这可能存在一定难度。这里要分享一种自适应布局的方法,它可以根据界面比例自动缩放内容控件,在较短时间内完成软件布局…...