FastAPI 路由与参数接收

1. FastAPI 启动方式

1.1 开发环境(推荐)

1
fastapi dev main.py

特点:

  • 自动检测代码变化
  • 自动热重载(reload)
  • 适合开发调试

1.2 生产环境(推荐)

1
fastapi run main.py

特点:

  • 不开启热重载
  • 更适合部署环境

1.3 使用 Uvicorn 启动

如果没有配置 FastAPI CLI,可以直接使用 Python 模块启动:

1
python -m uvicorn main:app --reload

其中:

1
main:app

表示:

1
文件名:FastAPI实例变量

例如:

1
2
3
main.py

app = FastAPI()

实际开发中一般会写一个 .ps1 脚本:

1
2
3
4
5
6
conda activate nangua_ai

python -m uvicorn main:app `
--host 0.0.0.0 `
--port 8000 `
--reload

2. FastAPI 路由基础

创建应用:

1
2
3
from fastapi import FastAPI

app = FastAPI()

3. 路径参数 Path Parameter

示例

1
2
3
4
5
@app.get("/greet/{name}")
async def greet_name(name: str) -> dict:
return {
"message": f"Hello {name}"
}

请求:

1
GET http://127.0.0.1:8000/greet/Nangua

执行过程:

1
2
3
4
5
6
7
8
9
URL
|
| /greet/Nangua
|
FastAPI解析
|
name="Nangua"
|
调用函数

结果:

1
2
3
{
"message": "Hello Nangua"
}

这里:

1
{name}

表示路径参数。

函数:

1
name: str

接收这个值。


4. 查询参数 Query Parameter

示例

1
2
3
4
5
@app.get("/greet")
async def greet_name(name: str) -> dict:
return {
"message": f"Hello {name}"
}

请求:

1
GET /greet?name=Nangua

FastAPI发现:

1
URL里面没有{name}

但是:

1
name: str

存在。

所以自动认为:

1
name 是 Query 参数

路径参数 vs 查询参数

写法 类型 请求
/greet/{name} Path /greet/Nangua
/greet?name=Nangua Query /greet?name=Nangua

5. 可选查询参数

5.1 默认值

1
2
3
4
5
6
7
@app.get("/greet")
async def greet_name(
name: str = "楠瓜"
):
return {
"message": f"Hello {name}"
}

请求:

1
/greet

返回:

1
2
3
{
"message":"Hello 楠瓜"
}

因为:

1
name="楠瓜"

提供了默认值。


5.2 允许 None

Python 3.10+

1
2
3
4
5
6
7
8
9
10
11
12
@app.get("/greet")
async def greet_name(
name: str | None = None
):
if name is None:
return {
"message":"Hello anonymous"
}

return {
"message":f"Hello {name}"
}

旧版本写法:

1
2
3
from typing import Optional

name: Optional[str] = None

6. 请求头 Header

请求头不是 Query。

需要显式告诉 FastAPI:

从 Header 获取


获取请求头

1
2
3
4
5
6
7
8
9
10
from fastapi import Header


@app.get("/items")
def read_items(
user_agent: str | None = Header(default=None)
):
return {
"User-Agent": user_agent
}

请求:

1
GET /items

请求头:

1
User-Agent: Chrome

结果:

1
2
3
{
"User-Agent":"Chrome"
}

原理

普通参数:

1
name:str

默认:

1
Query

但是:

1
user_agent:str = Header(...)

告诉 FastAPI:

1
去 Header 里面找

7. 响应头 Response Header

响应头不是接收参数。

它属于:

FastAPI 注入对象


示例:

1
2
3
4
5
6
7
8
9
10
11
from fastapi import Response


@app.get("/items")
def read_items(response: Response):

response.headers["X-My-Header"] = "hello"

return {
"msg":"ok"
}

返回:

Body:

1
2
3
{
"msg":"ok"
}

响应头:

1
X-My-Header: hello

为什么 Response 可以直接使用?

因为:

1
response: Response

不是让用户传入参数。

而是告诉 FastAPI:

我要一个 Response 对象,请帮我创建

类似:

1
2
3
4
5
6
7
# FastAPI内部伪代码

response = Response()

result = read_items(
response=response
)

所以:

1
response: Response

属于:

1
依赖注入

不是:

1
请求参数

8. 请求体 Body(重点)

请求体主要用于:

  • POST
  • PUT
  • PATCH

例如:

用户注册:

1
2
3
4
5
{
"username":"nangua",
"password":"123456",
"age":18
}

这个数据不是:

1
URL参数

而是:

1
Request Body

9. 使用 Pydantic Model 接收请求体

FastAPI 推荐方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pydantic import BaseModel


class User(BaseModel):
username: str
password: str
age: int


@app.post("/users")
async def create_user(
user: User
):
return {
"username": user.username,
"age": user.age
}

请求:

1
POST /users

Body:

1
2
3
4
5
{
"username":"Nangua",
"password":"123456",
"age":18
}

FastAPI自动:

  1. 读取 JSON
  2. 转换 Python 对象
  3. 校验类型
  4. 注入函数

等价:

1
2
3
4
5
user = User(
username="Nangua",
password="123456",
age=18
)

10. 请求体自动校验

例如:

发送:

1
2
3
4
{
"username":"Nangua",
"age":"abc"
}

但是模型:

1
2
class User(BaseModel):
age:int

FastAPI 自动返回:

1
2
3
4
5
6
7
8
9
{
"detail":[
{
"type":"int_parsing",
"loc":["body","age"],
"msg":"Input should be a valid integer"
}
]
}

不需要自己写:

1
2
if age不是数字:
return error

11. Body + Query 混合使用

可以同时存在:

1
2
3
4
5
6
7
8
9
@app.post("/users")
async def create_user(
user: User,
token: str
):
return {
"token":token,
"user":user
}

请求:

1
POST /users?token=abc

Body:

1
2
3
4
5
{
"username":"Nangua",
"password":"123456",
"age":18
}

FastAPI自动判断:

参数 来源
user Body
token Query

12. FastAPI 参数来源总结

FastAPI 判断参数来源规则:

有明确来源标记

优先:

1
2
3
4
5
6
7
Path()
Query()
Header()
Body()
Cookie()
Form()
File()

例如:

1
2
3
4
5
id:int = Path()

token:str = Header()

data:User = Body()

没有标记

默认:

简单类型

1
2
name:str
age:int

认为:

1
Query

Pydantic模型

1
user:User

认为:

1
Body

最终记忆:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
简单类型
|
|-- 无标记 --> Query


Pydantic模型
|
|-- 无标记 --> Body


显式声明
|
|-- Header()
|-- Path()
|-- Query()
|-- Body()

这套规则基本覆盖 FastAPI 90% 的参数处理逻辑。熟悉后,看接口代码基本一眼就能判断每个参数来自哪里。



本站由 楠瓜 使用 Stellar 1.33.1 主题创建。
风起于青萍之末,浪成于微澜之间。