FastAPI参数类型与请求格式详解:Query、Form、Body、File与Content-Type的对应关系
1. 引言
FastAPI作为现代Python Web框架,其参数处理机制非常灵活。理解Query、Form、Body、File参数类型与不同Content-Type的对应关系,对于正确构建API接口至关重要。本文将详细解析FastAPI中各种参数类型及其与HTTP请求格式的映射关系。
2. FastAPI参数类型概述
2.1 参数类型分类
FastAPI提供了多种参数类型来处理不同来源的请求数据:
- Query: URL查询参数
- Path: URL路径参数
- Form: 表单数据参数
- Body: 请求体参数
- File: 文件上传参数
- Header: HTTP头部参数
- Cookie: Cookie参数
2.2 参数类型与数据来源
参数类型 | 数据来源 | 用途 |
---|---|---|
Query | URL查询字符串 | 过滤、分页、搜索参数 |
Path | URL路径 | 资源标识符 |
Form | 表单数据 | HTML表单提交 |
Body | 请求体 | JSON数据 |
File | 文件上传 | 文件处理 |
3. Query参数详解
3.1 Query参数基本用法
Query参数是从URL的查询字符串中提取的数据,格式为?key=value&key2=value2
。
from fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: str = Query(...)):return {"query": q}
3.2 Query参数验证
FastAPI提供了丰富的验证选项来确保参数质量:
@app.get("/search/")
async def search_items(q: str = Query(..., min_length=3, # 最小长度max_length=50, # 最大长度regex="^[a-zA-Z]+$" # 正则表达式),page: int = Query(1, ge=1, le=100),sort_by: str = Query(default="created_at",enum=["created_at", "updated_at", "name"])
):return {"query": q, "page": page, "sort_by": sort_by}
(1)这里定义了一个名为q的查询参数:
- ... 表示该参数是必需的(没有默认值)
- min_length=3 指定参数最小长度为3个字符
- max_length=50 指定参数最大长度为50个字符
- regex="^[a-zA-Z]+$" 指定参数必须只包含英文字母(大小写均可),不能包含数字或其他字符
(2)定义了一个名为page的整数查询参数:
- 默认值为1
- ge=1 表示值必须大于等于1
- le=100 表示值必须小于等于100
(3)定义了一个名为sort_by的字符串查询参数:
- 默认值为"created_at"
- enum指定了允许的值列表,只能是"created_at"、"updated_at"或"name"中的一个
3.3 列表查询参数
@app.get("/filters/")
async def apply_filters(tags: list[str] = Query(default=[], description="标签列表")
):return {"tags": tags}
4. Form参数详解
4.1 Form参数基本概念
Form参数用于处理application/x-www-form-urlencoded
格式的数据,通常来自HTML表单提交。
from fastapi import FastAPI, Formapp = FastAPI()@app.post("/login")
async def login(username: str = Form(...), password: str = Form(...)):return {"username": username}
4.2 多值表单参数
@app.post("/tags")
async def create_tags(tags: list[str] = Form(...)):return {"tags": tags}
5. Body参数详解
5.1 Body参数基本用法
Body参数用于处理application/json
格式的数据,是RESTful API中最常用的数据传输方式。
from fastapi import FastAPI, Body
from pydantic import BaseModelclass User(BaseModel):name: strage: intemail: str@app.post("/users")
async def create_user(user: User = Body(...)):return user
5.2 原始JSON数据处理
@app.post("/raw-data")
async def raw_data( dict = Body(...)):return data
6. File参数详解
6.1 文件上传基础
File参数用于处理multipart/form-data
格式的文件上传请求。
from fastapi import FastAPI, File, UploadFile@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):return {"filename": file.filename,"content_type": file.content_type,"size": len(await file.read())}
6.2 多文件上传
@app.post("/upload-multiple")
async def upload_multiple(files: list[UploadFile] = File(...)):results = []for file in files:results.append({"filename": file.filename,"content_type": file.content_type})return {"files": results}
7. Content-Type与参数类型映射关系
7.1 标准映射关系表
FastAPI参数 | HTTP Content-Type | 数据格式 | 使用场景 |
---|---|---|---|
Query | 无 | URL参数 | 过滤、分页、搜索 |
Path | 无 | URL路径 | 资源标识 |
Form | application/x-www-form-urlencoded | 键值对 | HTML表单 |
Form | multipart/form-data | 键值对+文件 | 表单+文件 |
Body | application/json | JSON | API数据传输 |
File | multipart/form-data | 二进制文件 | 文件上传 |
7.2 具体示例说明
7.2.1 JSON请求示例
@app.post("/users")
async def create_user(user: User):return user
HTTP请求:
POST /users HTTP/1.1
Content-Type: application/json{"name": "张三","email": "zhang@example.com","age": 25
}
7.2.2 表单请求示例
@app.post("/login")
async def login(username: str = Form(...), password: str = Form(...)):return {"username": username}
HTTP请求:
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencodedusername=zhang&password=123456
7.2.3 文件上传请求示例
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):return {"filename": file.filename}
HTTP请求:
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=------boundary
Content-Disposition: form-data; name="file"; filename="avatar.jpg"
Content-Type: image/jpeg[文件二进制数据]
--boundary--
8. 混合参数使用
Content-Type限制
需要注意的是,单个HTTP请求只能使用一种Content-Type:
# ❌ 错误示例:不能同时使用application/json和multipart/form-data
@app.post("/wrong-example")
async def wrong_example(user: User = Body(...), # 需要application/jsonfile: UploadFile = File(...) # 需要multipart/form-data
):pass# ✅ 正确示例:统一使用multipart/form-data
@app.post("/correct-example")
async def correct_example(name: str = Form(...),age: int = Form(...),avatar: UploadFile = File(...)
):return {"name": name, "age": age, "avatar": avatar.filename}
9. API测试工具使用指南
9.1 Postman中的请求格式
JSON请求配置
- Body → raw → JSON
- Content-Type自动设置为application/json
表单请求配置
- Body → form-data 或 x-www-form-urlencoded
- Content-Type设置为application/x-www-form-urlencoded
文件上传配置
- Body → form-data
- 字段类型选择File
- Content-Type设置为multipart/form-data
9.2 Apifox中的JSON与Raw选项
JSON选项特点
- 自动设置Content-Type为application/json
- 提供JSON语法验证
- 支持格式化和语法高亮
Raw选项特点
- 可选择多种数据格式
- 手动设置Content-Type
- 支持JSON、XML、HTML、纯文本等格式
10. 实际应用案例
10.1 用户注册接口
from fastapi import FastAPI, Form, File, UploadFile
from pydantic import BaseModel
from typing import Optionalclass UserRegistration(BaseModel):username: stremail: strage: int@app.post("/register")
async def register_user(username: str = Form(..., max_length=50),email: str = Form(..., regex=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"),age: int = Form(..., ge=18, le=100),avatar: Optional[UploadFile] = File(None),profile: UserRegistration = None
):result = {"username": username,"email": email,"age": age}if avatar:result["avatar_filename"] = avatar.filenamereturn result
10.2 文件上传接口
@app.post("/upload-profile")
async def upload_profile(username: str = Form(...),bio: str = Form(default=""),avatar: UploadFile = File(...),documents: list[UploadFile] = File(default=[])
):return {"username": username,"bio": bio,"avatar": avatar.filename,"document_count": len(documents)}
11. 最佳实践建议
11.1 参数验证策略
- 使用Pydantic模型进行复杂数据验证
- 为必填参数使用
...
标记 - 为可选参数设置合理的默认值
- 使用验证装饰器确保数据质量
11.2 Content-Type选择原则
- 简单键值对使用
application/x-www-form-urlencoded
- 复杂数据结构使用
application/json
- 文件上传使用
multipart/form-data
- 避免在同一请求中混合不同Content-Type