You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI:解决HTTP多部分请求传递字典/JSON数据的422错误

FastAPI同时接收文件与表单JSON参数的422错误解决

问题场景

客户端请求代码(requests库)

import requests

files = {'template': open('template.xlsx', 'rb')}
payload = {
    'context': {
        'OUT': 'csv',
        'SHORT': 'short'
    },
    'filename': 'file.xlsx',
    'content_type': 'application/excel'
}

r = requests.post('http://localhost:8000/render', files=files, data=payload)

服务端代码(FastAPI)

from fastapi import FastAPI, UploadFile, Form
from pydantic import Json

app = FastAPI()

@app.post('/render')
def render(template: UploadFile, context: Json = Form(), filename: str = Form(...), content_type: str = Form(...)):
    # processing
    return "ok"

错误信息

{"detail":[{"loc":["body","context"],"msg":"Invalid JSON","type":"value_error.json"}]}

错误原因

当使用requests发送包含文件的multipart/form-data请求时,字典类型的context会被自动序列化为带单引号的字符串(如{'OUT': 'csv', 'SHORT': 'short'})。而FastAPI的Json类型参数要求接收标准JSON格式字符串(必须用双引号),因此解析失败,返回422验证错误。

服务端修复方案

方案1:自定义依赖项手动解析

通过自定义依赖函数,在参数进入视图前完成格式转换,兼容单引号的字符串格式:

from fastapi import FastAPI, UploadFile, Form, Depends, HTTPException
import json
from typing import Dict

app = FastAPI()

def get_context(context_str: str = Form(...)) -> Dict:
    try:
        # 替换单引号为双引号,适配requests传递的格式
        normalized_str = context_str.replace("'", "\"")
        return json.loads(normalized_str)
    except json.JSONDecodeError:
        raise HTTPException(status_code=422, detail="Invalid context JSON format")

@app.post('/render')
def render(
    template: UploadFile, 
    context: Dict = Depends(get_context), 
    filename: str = Form(...), 
    content_type: str = Form(...)
):
    # 处理逻辑
    return {"status": "ok", "received_context": context}

方案2:使用Pydantic模型做结构化验证与转换

如果需要对context的字段做合法性校验,可以结合Pydantic模型的验证器:

from fastapi import FastAPI, UploadFile, Form, HTTPException
from pydantic import BaseModel, field_validator
import json

app = FastAPI()

class ContextModel(BaseModel):
    OUT: str
    SHORT: str

    @field_validator('*', mode='before')
    def parse_and_validate(cls, value):
        if isinstance(value, str):
            try:
                normalized_str = value.replace("'", "\"")
                return json.loads(normalized_str)
            except json.JSONDecodeError:
                raise ValueError("Invalid JSON format for context")
        return value

@app.post('/render')
def render(
    template: UploadFile, 
    context: ContextModel = Form(...), 
    filename: str = Form(...), 
    content_type: str = Form(...)
):
    # 处理逻辑
    return {"status": "ok", "received_context": context.dict()}

说明

两种方案都能在服务端完成格式转换,无需修改客户端代码。方案2额外提供了字段级别的合法性校验,适合对参数格式有严格要求的场景。

内容的提问来源于stack exchange,提问作者Альберт Александров

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 13:45:26