FastAPI 接收 PHP 发送的 JSON 字符串并自动解析为字典
fastapi 默认将请求体视为结构化数据,但当 php 以 raw string 方式发送 json(如 '{"test":"no","fields":"x"}')时,fastapi 会将其当作字符串而非 dict 导致验证失败;本文介绍如何通过 pydantic 模型预处理实现自动 json 字符串转字典。
fastapi 默认将请求体视为结构化数据,但当 php 以 raw string 方式发送 json(如 '{"test":"no","fields":"x"}')时,fastapi 会将其当作字符串而非 dict 导致验证失败;本文介绍如何通过 pydantic 模型预处理实现自动 json 字符串转字典。
在实际前后端交互中,PHP 脚本常使用 curl 以 Content-Type: text/plain 或未正确设置 application/json 的方式发送 JSON 数据,导致 FastAPI 接收到的是JSON 格式的字符串(例如 "{"test":"No","fields":"X"}"),而非已解析的 Python 字典。此时若直接声明参数为 input_data: dict,Pydantic 2.x 会因类型不匹配抛出 dict_type 错误。
解决思路是:不改变前端发送方式,而在 FastAPI 后端通过 Pydantic 模型的 @field_validator(mode='before') 钩子,在验证前对原始输入进行 JSON 解析。
以下是完整、健壮的实现方案:
import json
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, field_validator
app = FastAPI()
class InputData(BaseModel):
input_data: dict
@field_validator("input_data", mode="before")
def parse_json_string(cls, v):
# 若输入为字符串且看起来像 JSON,则尝试解析
if isinstance(v, str):
try:
parsed = json.loads(v.strip())
if not isinstance(parsed, dict):
raise ValueError("Parsed JSON is not a dictionary")
return parsed
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON string: {e}")
# 若已是 dict,直接返回(兼容正常 JSON 请求)
elif isinstance(v, dict):
return v
else:
raise ValueError(f"Unsupported input type: {type(v).__name__}")
@app.post("/post")
async def post(payload: InputData):
# 此时 payload.input_data 已确保为 dict 类型
return {
"received": payload.input_data,
"type": type(payload.input_data).__name__
}
✅ 关键特性说明:
YouArt
YouArt是个一站式AI图像与视...
- ✅ 容错性强:自动识别字符串输入并解析,同时兼容标准 application/json 请求(即已解析的 dict);
- ✅ 类型安全:校验解析结果是否为 dict,避免嵌套数组等非法结构;
- ✅ 错误友好:捕获 JSONDecodeError 并转换为清晰的 Pydantic 验证错误,便于调试;
- ✅ 零侵入前端:PHP 无需修改发送逻辑(如仍可使用 curl_setopt($ch, CURLOPT_POSTFIELDS, $json_str))。
⚠️ 注意事项:
- 确保 PHP 请求头明确指定 Content-Type: application/json(推荐)或至少不设为 text/plain——虽然上述方案可兜底,但规范 header 更利于长期维护;
- 若需支持嵌套结构或复杂字段校验,建议进一步扩展 InputData 模型,定义具体字段而非泛用 dict;
- 生产环境建议添加日志记录异常输入,便于追踪异常 PHP 客户端行为。
该方案兼顾兼容性与健壮性,是处理“非标准 JSON 传输”场景下的推荐实践。