fastapi 请求参数校验机制
"""
第二步:根据类型提示自动转换/校验参数
目标:搞懂「内省(introspection)」—— 程序在运行时读自己函数的
参数名和类型注解,据此自动处理参数。
对应 fastapi 里的:你写 def f(x: int),客户端传 "2",fastapi 自动给你 2(int)。
真实请求里参数都是字符串,框架负责按类型转换 + 校验。
"""
import inspect
class App:
def __init__(self):
self.routes = {}
def get(self, path):
def decorator(func):
self.routes[("GET", path)] = func
return func
return decorator
def handle(self, method, path, raw_params: dict):
"""
模拟一个请求到来。
raw_params 模拟从 URL / 表单里拿到的原始参数,值全是字符串
(就像真实 HTTP 里那样)。
"""
func = self.routes.get((method, path))
if func is None:
return "404 Not Found"
# ---- 这里是本步的核心:按类型提示转换参数 ----
kwargs = {}
sig = inspect.signature(func) # 内省:读出函数签名
for name, param in sig.parameters.items():
type_ = param.annotation # 拿到该参数的类型,比如 int
raw_value = raw_params.get(name)
if raw_value is None:
if param.default is not inspect.Parameter.empty:
raw_value = param.default
if type_ is inspect.Parameter.empty:
# 没写类型注解,就原样传字符串
kwargs[name] = raw_value
else:
try:
kwargs[name] = type_(raw_value) # 用类型当转换函数:int("2") -> 2
except (ValueError, TypeError):
return f"422 参数 {name}={raw_value!r} 无法转换成 {type_.__name__}"
return func(**kwargs) # 用转换好的参数调用业务函数
app = App()
@app.get("/add")
def add(x: int, y: int):
return x + y
@app.get("/repeat")
def repeat(text: str, times: int):
return text * times
@app.get("/devide")
def devide(x: float, y: float = 2):
return x / y
if __name__ == "__main__":
# 注意:传进去的值全是字符串(模拟真实请求)
print('/add x="2" y="3" ->', app.handle("GET", "/add", {"x": "2", "y": "3"}))
print('/repeat text="ab" times="3" ->', app.handle("GET", "/repeat", {"text": "ab", "times": "3"}))
print()
# 故意制造错误,看校验生效
print('/add x="hello" y="3" ->', app.handle("GET", "/add", {"x": "hello", "y": "3"}))
print('/add 缺 y ->', app.handle("GET", "/add", {"x": "2"}))
# 我自己加的 /devide path
print('/devide x="8.6" y="2" ->', app.handle("GET", "/devide", {"x": "8.6", "y": "2"}))
print('/devide x="8.6" ->', app.handle("GET", "/devide", {"x": "8.6"}))
输出结果:
/add x="2" y="3" -> 5
/repeat text="ab" times="3" -> ababab
/add x="hello" y="3" -> 422 参数 x='hello' 无法转换成 int
/add 缺 y -> 422 参数 y=None 无法转换成 int
/devide x="8.6" y="2" -> 4.3
/devide x="8.6" -> 4.3

浙公网安备 33010602011771号