FastAPI POST接口含可选参数返回400错误(OpenAI应用)
问题原因分析
请求格式不匹配:
- 你的
process_user_query函数中,text参数默认被识别为查询参数(未用Body或Pydantic模型标记),但调用时用requests.post发送了JSON数组[{"text": "..."}],FastAPI无法解析这种格式,直接返回400错误。 - 当端点包含
UploadFile参数时,FastAPI默认要求请求为multipart/form-data格式,但你发送的是application/json格式,也会导致参数解析失败。
- 你的
参数定义与调用不匹配:
- 未明确
text参数的来源(JSON体/查询参数/表单),FastAPI无法正确绑定参数。 - 调用时的payload是数组结构,但端点期望单个键值对。
- 未明确
解决方案
方案1:拆分端点,分别处理文本与文件请求
拆分端点让逻辑更清晰,分别支持JSON文本请求和文件上传请求:
后端代码修改
from dotenv import load_dotenv load_dotenv() from fastapi import APIRouter, HTTPException, UploadFile, File, Body import base64 import os from ai_interaction.prompt import assemble_prompt from ai_interaction.llm import stream_openai_response router = APIRouter() # 处理JSON格式的文本请求 @router.post("/query/text") async def process_text_query(text: str = Body(...)): print("Received text:", text) api_key = os.getenv("OPENAI_API_KEY") if not api_key: raise HTTPException(status_code=500, detail="API key not configured.") if not text: raise HTTPException(status_code=400, detail="No text provided.") image_url = text # 后续可添加URL验证逻辑 prompt = assemble_prompt(image_url) response = await stream_openai_response(prompt, api_key) return {"response": response} # 处理multipart格式的文件上传请求 @router.post("/query/file") async def process_file_query(file: UploadFile = File(...)): print("Received file:", file) api_key = os.getenv("OPENAI_API_KEY") if not api_key: raise HTTPException(status_code=500, detail="API key not configured.") if not file: raise HTTPException(status_code=400, detail="No file provided.") image_url = await process_uploaded_file(file) prompt = assemble_prompt(image_url) response = await stream_openai_response(prompt, api_key) return {"response": response} async def process_uploaded_file(file: UploadFile): content = await file.read() base64_encoded = base64.b64encode(content).decode('utf-8') file_url = f"data:{file.content_type};base64,{base64_encoded}" await file.close() return file_url
文本请求调用代码
import requests url = "http://localhost:8000/api/query/text" payload = {"text": "Explain the water molecule structure"} response = requests.post(url, json=payload) print("Status Code:", response.status_code) print("Response Body:", response.json())
文件上传调用代码
import requests url = "http://localhost:8000/api/query/file" files = {"file": open("your_image.jpg", "rb")} response = requests.post(url, files=files) print("Status Code:", response.status_code) print("Response Body:", response.json())
方案2:单个端点同时支持表单文本与文件上传
如果必须用同一个端点,用Form接收文本,统一使用multipart/form-data格式:
后端代码修改
from dotenv import load_dotenv load_dotenv() from fastapi import APIRouter, HTTPException, UploadFile, File, Form import base64 import os from ai_interaction.prompt import assemble_prompt from ai_interaction.llm import stream_openai_response router = APIRouter() @router.post("/query") async def process_user_query(text: str = Form(None), file: UploadFile = File(None)): print("Received text:", text) print("Received file:", file) api_key = os.getenv("OPENAI_API_KEY") if not api_key: raise HTTPException(status_code=500, detail="API key not configured.") if not text and not file: raise HTTPException(status_code=400, detail="No text or file provided.") if text: image_url = text # 后续可添加URL验证逻辑 elif file: image_url = await process_uploaded_file(file) prompt = assemble_prompt(image_url) response = await stream_openai_response(prompt, api_key) return {"response": response} async def process_uploaded_file(file: UploadFile): content = await file.read() base64_encoded = base64.b64encode(content).decode('utf-8') file_url = f"data:{file.content_type};base64,{base64_encoded}" await file.close() return file_url
文本请求调用代码
import requests url = "http://localhost:8000/api/query" payload = {"text": "Explain the water molecule structure"} response = requests.post(url, data=payload) print("Status Code:", response.status_code) print("Response Body:", response.json())
文件上传调用代码
import requests url = "http://localhost:8000/api/query" files = {"file": open("your_image.jpg", "rb")} response = requests.post(url, files=files) print("Status Code:", response.status_code) print("Response Body:", response.json())
关键注意点
- 只要端点包含
UploadFile或File参数,FastAPI默认强制要求请求为multipart/form-data格式,此时无法用JSON传参,需用Form组合处理。 - 调用时不要传数组格式的payload,需用单个键值对的字典。
内容的提问来源于stack exchange,提问作者Narsil91
相关产品推荐
相关产品推荐

