使用Fetch API发表单数据时FastAPI返回422错误的排查求助
问题:Fetch API发送FormData到FastAPI时出现422/400错误
使用JavaScript的Fetch API发送FormData到FastAPI后端时,点击提交后收到Error 422: Unprocessable entity;手动添加Content-Type: multipart/form-data请求头则出现Error 400: Bad Request。
前端原代码
function register() { var formData = new FormData(); var textInputName = document.getElementById('textInputName'); var sexButtonActive = document.querySelector('#buttonsMW > .btn.active'); var imagesInput = document.getElementById('imagesInput'); formData.append('name', textInputName.value); if (sexButtonActive != null){ formData.append('sex', sexButtonActive.html()) } else { formData.append('sex', ""); } formData.append('images', imagesInput.files[0]); fetch('/user/register', { method: 'POST', data: formData, }) .then(response => response.json()); } document.querySelector("form").addEventListener("submit", register);
后端原代码
@app.post("/user/register", status_code=201) def register_user(name: str = Form(...), sex: str = Form(...), images: List[UploadFile] = Form(...)): try: print(name) print(sex) print(images) return "OK" except Exception as err: print(err) print(traceback.format_exc()) return "Error"
错误原因分析
- Fetch参数误用:Fetch API发送请求体的参数是
body,不是data,原代码的data: formData会导致后端接收不到表单数据,触发422错误。 - Content-Type手动设置错误:发送FormData时,浏览器会自动生成带
boundary的multipart/form-data请求头(如multipart/form-data; boundary=----WebKitFormBoundaryxxx),手动添加不带boundary的请求头会让后端无法解析表单边界,引发400错误。 - DOM元素取值错误:
sexButtonActive.html()是jQuery方法,原生JS需用textContent或innerHTML获取内容,原代码此处会抛出错误,导致sex字段无法正确设置。 - 文件接收类型不匹配:前端仅添加单个文件,但后端用
List[UploadFile]接收多文件,类型不匹配触发422错误。
修复方案
1. 前端代码修复
function register(e) { // 阻止表单默认提交,避免页面刷新中断请求 e.preventDefault(); var formData = new FormData(); var textInputName = document.getElementById('textInputName'); var sexButtonActive = document.querySelector('#buttonsMW > .btn.active'); var imagesInput = document.getElementById('imagesInput'); formData.append('name', textInputName.value); if (sexButtonActive != null){ // 原生JS用textContent获取文本内容 formData.append('sex', sexButtonActive.textContent.trim()) } else { formData.append('sex', ""); } // 单文件场景:添加第一个文件;多文件则循环append所有文件 if (imagesInput.files.length > 0) { formData.append('images', imagesInput.files[0]); } fetch('/user/register', { method: 'POST', // 用body代替data传递请求体 body: formData // 无需手动设置Content-Type,浏览器自动处理 }) .then(response => response.json()) .catch(err => console.error('请求错误:', err)); } document.querySelector("form").addEventListener("submit", register);
2. 后端代码修复
根据文件接收需求调整:
- 单文件接收:将
List[UploadFile]改为UploadFile - 多文件接收:前端循环append所有文件(
for (let file of imagesInput.files) { formData.append('images', file); }),后端保持List[UploadFile]
修复后的后端代码(单文件场景):
from fastapi import FastAPI, Form, UploadFile import traceback app = FastAPI() @app.post("/user/register", status_code=201) def register_user(name: str = Form(...), sex: str = Form(...), images: UploadFile = Form(...)): try: print(name) print(sex) print(images.filename) return {"status": "OK"} except Exception as err: print(err) print(traceback.format_exc()) return {"status": "Error"}
内容的提问来源于stack exchange,提问作者Egor Richman
相关产品推荐
相关产品推荐

