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 传输”场景下的推荐实践。

相关推荐:

为什么Python爬虫在解析复杂表格时推荐使用Pandas库?

pandas.read_html能自动解析HTML表格并修复合并单元格、多级表头等结构,但需合理配置match、header、skiprows等参数,并处理JS渲染、数据类型、空值等问题,否则易导致列错位、类型错误等隐患。 因为pandas.read_html能直接把HTML表格转成DataFram...

为什么特征降维后的梯度下降反而更慢?——解析 NumPy 循环开销与向量化优化

本文揭示了在使用svd降维后梯度下降运行时间不降反升的根本原因:原始实现中嵌套python循环和动态列表操作主导了耗时,而非矩阵运算本身;通过向量化重写(消除外层学习率循环、预分配数组、批量更新参数),可使小规模特征集真正发挥计算优势。 本文揭示了在使用svd降维后梯度下降运行时间不降反升的根本原因...

Pandas DataFrame.info() 方法的行为解析与正确使用指南

DataFrame.info()是一个用于打印数据框结构摘要的工具方法,它不返回任何值(即返回None),因此直接赋值会导致变量为None;正确用法是单独调用该方法,而非赋值。 `dataframe.info()`是一个用于打印数据框结构摘要的工具方法,它不返回任何值(即返回`none`),因此直接...

怎么优化Python中的字符串拼接操作以避免频繁的内存分配?

+拼接在循环中特别慢,因字符串不可变,每次s=s+item都新建对象并复制全部内容,时间复杂度达O(n²),引发大量内存分配与垃圾回收;推荐用list.append()+''.join()降至O(n)。 为什么+拼接字符串在循环里特别慢? Python中的字符串是不可变对象,每次用+拼接都会创建新字...