应使用query的ge/le等参数进行数值范围校验,而非手动if判断;path参数类型声明导致404而非422;自定义校验需用pydantic的@field_validator并置于basemodel中。

Query参数怎么限制数值范围才不被绕过
FastAPI的Query本身不拦截非法类型,只做类型转换后校验;如果传了字符串"abc"给期望int的Query,会直接报422 Unprocessable Entity,但这是在解析阶段失败,不是你写的校验逻辑生效——这点容易误以为“校验没起作用”。
真正要约束数值范围(比如age必须在0–150之间),得靠Field的ge/le参数,而不是自己写if判断:
from fastapi import Query, Field from pydantic import BaseModel <h1>✅ 正确:范围校验由Pydantic在解析时完成,且对None/缺失值也生效</h1><p>age: int = Query(..., ge=0, le=150)</p><h1>❌ 错误:下面这种写法不会触发校验,因为Query(...)本身不支持lambda或函数式约束</h1><h1>age: int = Query(..., lambda x: 0 </h1>
-
ge和le只对数字类型有效;字符串用min_length/max_length - 如果参数可选(即允许不传),把
...换成None,再加default=None,否则ge会强制要求传值 - 注意:
Query(0, ge=0)表示默认值是0且必须≥0——但用户不传时仍用默认值,不会校验;只有显式传了值才会校验
Path参数里用int还是str?为什么404比422更常见
Path参数类型声明直接影响路由匹配。如果你写user_id: int,FastAPI会在URL解析阶段就尝试转成int;失败就直接404(Not Found),根本不会进你的函数——这不是校验失败,是路由没匹配上。
例如访问/users/abc,而路径定义是/users/{user_id:int},结果就是404,不是422。很多人卡在这儿,以为是校验逻辑漏了,其实是类型声明让FastAPI提前拒掉了请求。
- 想让
/users/abc返回422(带详细错误信息),就把user_id声明为str,再在函数体内手动转int+捕获ValueError - 但更推荐保持
int声明,靠404区分“资源不存在”和“输入格式错误”,符合REST语义 - 若ID可能是UUID或混合字符串(如
usr_7f3a),必须用str,别硬转int
Query和Path混用时,谁的校验优先级更高
没有“优先级”一说——它们是并行校验的,各自独立触发。但出错时机不同:Path参数校验失败(如类型转不了)导致404;Query参数校验失败(如gt=10但传了5)导致422。如果两者都错,FastAPI只报第一个遇到的错误(通常是Path,因为它先解析URL路径)。
这会导致调试困惑:改了Query校验逻辑,却看不到错误反馈,因为Path已经先挂了。
- 开发时用
curl -v或Postman看真实HTTP状态码,别只盯返回体 - 测试要覆盖边界值:
/?limit=-1(Query校验)、/item/abc(Path解析)分开验证 - 不要依赖Query的默认值掩盖Path问题——比如
Path(...)没设默认,又没处理缺失,就永远收不到请求
自定义校验函数怎么写才不破坏OpenAPI文档
FastAPI靠Pydantic模型生成OpenAPI文档。直接在函数里用if判断,文档里完全体现不出来;用Field的gt/ge等,会自动写进schema的minimum/maximum字段。
真需要复杂逻辑(比如“start_time必须早于end_time”),得用Pydantic的@field_validator,且必须放在BaseModel里,不能塞在路径函数参数里。
from pydantic import BaseModel, field_validator
<p>class TimeRange(BaseModel):
start: int
end: int</p><pre class="brush:python;toolbar:false;">@field_validator('end')
def end_after_start(cls, v, info):
if 'start' not in info.data:
return v
if v <h1>然后在路由里用:</h1><h1>def read_items(range: TimeRange = Query(...)):</h1>
- 用
@field_validator而不是@validator(旧版已弃用) - 函数参数名必须是
cls,v,info,顺序不能错 - 文档能显示这个校验,但错误提示文字不会自动进OpenAPI;要提示友好,得在异常里写清楚
实际用下来,最难绷的是Path类型和404的耦合——它看着像服务端错误,其实是路由设计的一部分。别急着加try-except,先确认你是不是真的想让/users/xyz变成422。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











