文章目录
中间件
在 FastAPI 中,中间件是一个功能强大的组件,用于处理请求和响应之间的各种横切关注点(cross-cutting concerns)。中间件允许你在请求被处理前后执行代码,这非常适合实现如日志记录、安全控制、数据处理和跨域资源共享(CORS)等功能。
定义
中间件是介于接收请求和发送响应之间的一个软件层。在 FastAPI 应用中,所有的请求首先经过一系列的中间件,然后才到达实际的业务逻辑处理函数;响应也会在返回给客户之前经过这些中间件。因此,中间件是处理全局任务的理想选择。
使用
在 FastAPI 中添加中间件通常涉及几个步骤,其中涉及到选择合适的中间件组件并配置其参数。以下是一个如何设置 CORS 中间件的例子,这个中间件用于允许或限制跨域请求。
示例-配置 CORS 中间件
跨源资源共享(CORS)是一个安全特性,允许或限制网页上的资源可以被另一个域名的网页访问。在 API 开发中配置 CORS 是常见需求,尤其是当你的前端和后端部署在不同的域时。
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import os
app = FastAPI()
# 配置 CORS 中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["X-Custom-Header", "Content-Type"],
)
@app.get("/")
async def main():
return {"message": "Hello World"}
@app.post("/submit")
async def submit_form(data: dict):
return {"received_data": data}
if __name__ == "__main__":
uvicorn.run(
f"{os.path.basename(__file__).split('.')[0]}:app",
host="127.0.0.1",
port=8000,
reload=True,
)
解释说明
- 导入依赖
from fastapi import FastAPI
: 导入 FastAPI,用于创建 API 应用。from fastapi.middleware.cors import CORSMiddleware
: 导入 CORS 中间件,用于配置跨域资源共享。
- 应用实例
app = FastAPI()
: 创建一个 FastAPI 应用实例。
- 添加 CORS 中间件
app.add_middleware(CORSMiddleware, ...)
: 将 CORS 中间件添加到应用中。这一步是配置 CORS 支持的关键。
- CORS 中间件参数
allow_origins
: 定义哪些来源域可以访问资源。在此示例中,https://example.com
和https://www.anotherdomain.com
被允许访问。这可以是一个具体的域名列表或["*"]
(允许所有域)。
allow_credentials
: 允许前端在请求中携带认证信息(如 Cookies)。这是一个布尔值。allow_methods
: 指定允许的 HTTP 方法,如["GET", "POST", "PUT", "DELETE"]
。
allow_headers
: 允许的 HTTP 请求头列表,这里允许X-Custom-Header
和Content-Type
。
- API 端点
定义了两个端点
main()
和submit_form()
来演示如何在启用了 CORS 的应用中处理请求。
测试
allow_origins=[] # 不允许任何源
allow_origins=["*"] # 允许任何源
其他中间件
自定义日志记录中间件
自定义中间件可以用来实现例如日志记录等功能,这对于调试和监控应用状态非常有用。
from fastapi import FastAPI, Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import JSONResponse, PlainTextResponse
import time
import uvicorn
import os
class LoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
# 记录请求和响应的详细信息
log_message = (
f"请求方法: {request.method}\n"
f"请求路径: {request.url.path}\n"
f"响应状态: {response.status_code}\n"
f"处理时间: {process_time:.4f} 秒"
)
print(log_message) # 在生产环境中,可以将这些信息写入日志文件
return response
app = FastAPI()
# 添加中间件到应用中
app.add_middleware(LoggingMiddleware)
# 使用 PlainTextResponse 返回简单文本响应
@app.get("/", response_class=PlainTextResponse)
async def read_root():
# 可以直接返回字符串,FastAPI 会自动封装为 PlainTextResponse
return "Hello, World!"
# 使用 JSONResponse 创建一个更复杂的 JSON 响应
@app.post("/items/", response_class=JSONResponse)
async def create_item(item: dict):
# 检查输入是否包含必要的字段
if "name" not in item:
raise HTTPException(status_code=400, detail="Missing 'name' field in the item")
# 模拟创建项目并返回包含项目信息的响应
response_data = {"item_name": item.get("name"), "item_id": 123}
return JSONResponse(content=response_data, status_code=201)
if __name__ == "__main__":
uvicorn.run(
f"{os.path.basename(__file__).split('.')[0]}:app",
host="127.0.0.1",
port=8000,
reload=True,
)
解释说明
- 中间件类
LoggingMiddleware
:
- 继承自
BaseHTTPMiddleware
,重写dispatch
方法来拦截请求和发送的响应。 - 使用
call_next(request)
异步调用接下来的请求处理,这将返回一个响应对象。 - 计算处理请求所需的时间,并构建一个包含请求方法、路径、响应状态和处理时间的日志消息。
- 使用 print 函数打印日志信息。在实际应用中,选择使用
logging
模块或外部日志服务。
- 添加中间件:
- 使用
app.add_middleware(LoggingMiddleware)
将自定义中间件添加到 FastAPI 应用中。
- 示例端点:
- 定义两个简单的 API 端点,
read_root
和create_item
,用于演示日志中间件的效果。
测试
SessionMiddleware
使用
SessionMiddleware
来管理用户会话,这对于需要追踪用户状态或者保持登录状态的应用尤为重要。
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from starlette.middleware.sessions import SessionMiddleware
import uvicorn
import os
app = FastAPI()
# 设置 SessionMiddleware,secret_key 应该是一个长随机字符串
app.add_middleware(
SessionMiddleware, secret_key="!se1cret2-ke3y-sh4ould-b5e-ve8ry-se8cure!"
)
@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
# 访问会话中的数据
count = request.session.get("count", 0)
count += 1
request.session["count"] = count # 更新会话数据
return f"<html><body><h1>Visit Count: {count}</h1></body></html>"
@app.get("/reset")
async def reset_count(request: Request):
request.session.pop("count", None) # 重置会话数据
return {"status": "session reset"}
@app.get("/logout")
async def logout(request: Request):
request.session.clear() # 清空所有会话数据
return {"status": "logged out"}
if __name__ == "__main__":
uvicorn.run(
f"{os.path.basename(__file__).split('.')[0]}:app",
host="127.0.0.1",
port=8000,
reload=True,
)
功能说明
- 设置会话中间件:
- 使用 SessionMiddleware 来管理会话。secret_key 用于签名和/或加密会话 cookie,确保它的安全性。
- 首页 (/):
- 显示页面访问次数。每次访问都会增加计数,这个计数保存在会话中。
- 使用 HTMLResponse 直接返回 HTML 格式的响应。
- 重置计数 (/reset):
- 提供一个端点来重置会话中的 count 数据。这可以用于演示会话数据的修改。
- 注销 (/logout):
- 清空会话中的所有数据,模拟用户注销功能。
测试
访问次数
重置次数
清空会话并注销
TrustedHostMiddleware
使用
TrustedHostMiddleware
可以提高应用的安全性,限制哪些主机名可以访问应用。
from fastapi import FastAPI
from starlette.middleware.trustedhost import TrustedHostMiddleware
app = FastAPI()
# 添加 TrustedHostMiddleware
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=["example.com", "www.example.com", "*.example.com"]
)
@app.get("/")
async def read_root():
return {"message": "Hello, World!"}
功能说明
- 添加
TrustedHostMiddleware
中间件:
allowed_hosts
参数定义了可以接受请求的主机名列表。在这个例子中,允许从example.com
、www.example.com
,以及任何以example.com
结尾的子域名接受请求。- 可以根据需要调整这个列表来包括你的部署环境中的实际主机名。
- API 端点:
- 定义了一个简单的 GET 请求处理函数
read_root
,它返回一个简单的欢迎消息。
测试
与CORSMiddleware的区别
TrustedHostMiddleware
- 目的:
TrustedHostMiddleware
用于确保接收到的请求来自预定义的一组受信任的主机名。它的主要作用是防止 HTTP Host 头攻击,这种攻击可能会误导应用生成错误的链接、重定向、或被认为是不安全的请求来源。
- 工作原理:
- 当一个请求被接收时,
TrustedHostMiddleware
检查 HTTP 请求的 Host 头部是否在允许的主机名列表中。如果不在这个列表中,请求将被拒绝,并返回一个错误响应(通常是 400 Bad Request)。
- 使用场景:
适用于所有服务器端应用,特别是在面对公共互联网时,这有助于确保请求确实来自你预期的域。
CORSMiddleware
- 目的:
CORSMiddleware
旨在支持跨源资源共享 (CORS),允许或限制网页上的资源可以被不同源(域、协议或端口)的网页访问。CORS 主要用于前端 JavaScript 代码,使其能够请求并从不同源加载资源。
- 工作原理:
- CORS 策略要求在发送实际请求前,浏览器首先发送一个预检请求(使用 OPTIONS 方法),从服务器查询哪些源、哪些 HTTP 方法和头部是被允许的。如果服务器的响应表明这个跨源请求是被允许的,浏览器才会发送实际的请求。
- 使用场景:
- 主要用于控制哪些外部源可以访问你的资源,通常用于 API 服务,尤其是当 API 被不同的前端应用调用时。这有助于增加资源访问的灵活性,同时确保安全控制。
对比总结
- 安全目标不同
TrustedHostMiddleware
防止服务器被伪造的或不安全的 Host 头欺骗。CORSMiddleware
允许服务器明确声明哪些跨域请求是合法的,主要防止未授权的跨站读取和互动。
- 适用环境不同
TrustedHostMiddleware
主要用于服务器端安全防护,保护应用不受恶意请求影响。CORSMiddleware
主要解决浏览器同源策略的限制,允许合法的跨源访问。