使用JavaScript向本地FastAPI应用发送POST请求遇错求助
问题修复建议
问题背景
本地运行FastAPI应用,访问地址为http://localhost:8000,前端通过HTML内嵌JS发送POST请求时遇到CORS配置错误和请求格式问题,具体日志显示OPTIONS /add_points/ HTTP/1.1" 400 Bad Request和POST /add_points/ HTTP/1.1" 422 Unprocessable Entity,更换Fetch API后仍出现400错误。
FastAPI后端代码
from typing import Union from fastapi import FastAPI from pydantic import BaseModel from fastapi.middleware.cors import CORSMiddleware app = FastAPI() origins = [ "*" ''' "http://localhost:8000/add_points/", "http://localhost:8000/check_points/", "http://localhost:8000/check_item_points/", "http://localhost:8000/redeem_points/" ''' ] app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) users = {"matt": 0} items = {"ticket": 7} class User(BaseModel): name: str points: float item: str class AddTransaction(BaseModel): name: str points: float class UserPoints(BaseModel): name: str points: float class Item(BaseModel): name: str points: float # -----Post Requests----- @app.post("/add_points/") def add_points(add_transaction: AddTransaction): global users user_id = add_transaction.name points = add_transaction.points users[user_id] = users.get(user_id, 0) + points return users[user_id] @app.post("/check_points/") def check_points(user_points: UserPoints): global users user_id = user_points.name points = user_points.points return users[user_id], points @app.post("/check_item_points/") def check_item_points(item: Item): global items item_id = item.name points = item.points return item[item_id], points @app.post("/redeem_points/") def redeem_points(add_transaction: AddTransaction, user_points: UserPoints, item: Item, user: User): global users global items user_id = add_transaction.name user_points = user_points.points item_points = item.points item_pre = item.name item_post = user.item if user_points >= item_points: user_points == user_points - item_points item_post == item_pre return users[user_id], users[user_points], users[item_post] else: return "insufficient funds" # -----Get Requests----- @app.get("/") def read_root(): return {"Hello": "World"} # -----Put Requests----- """" @app.put("/items/{item_id}") def update_item(item_id: int, item:Item): return {"item_name": item.name, "item_id": item_id} """ if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
原始前端HTML代码
<!DOCTYPE html> <html> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <body> <br><br><br><span style="text-align: center;"><button id="send">Send Request</button></span> </body> <script> $("#send").on("click", evt => { $.post("http://localhost:8000/add_points/", { name: "string", points: 5.0 }, function(data, status){ alert("Data: " + data + "\nStatus: " + status); }); }); </script> </html>
错误日志
INFO: 127.0.0.1:49413 - "OPTIONS /add_points/ HTTP/1.1" 400 Bad Request
INFO: 127.0.0.1:49413 - "POST /add_points/ HTTP/1.1" 422 Unprocessable Entity
更新后的Fetch API代码
const url = new URL('localhost:8000/add_points/'); $("#send").on("click", evt => { fetch(url, { method: 'POST', headers: {'Accept': 'application/json', 'Content-Type': 'application/json'}, body: JSON.stringify({"name":"John", "points":50.0}) }).then().catch((error) => { console.log(error.message); }); });
修复步骤
1. 修复CORS配置语法错误
后端origins数组中,多行字符串会被当作无效的数组元素,导致CORS中间件解析失败,引发OPTIONS请求400错误。修正为:
origins = [ "*" # 生产环境建议替换为具体允许的域名,如"http://localhost:8080" ]
2. 修复Fetch API的URL问题
Fetch代码中URL缺少http://协议头,浏览器会将其识别为相对路径,导致请求地址错误。修正为:
const url = new URL('http://localhost:8000/add_points/');
3. 修复jQuery请求的内容类型
jQuery的$.post默认发送application/x-www-form-urlencoded格式数据,但FastAPI的Pydantic模型期望application/json格式,需显式设置请求头:
$("#send").on("click", evt => { $.ajax({ url: "http://localhost:8000/add_points/", method: "POST", contentType: "application/json", data: JSON.stringify({ name: "string", points: 5.0 }), success: function(data, status){ alert("Data: " + data + "\nStatus: " + status); }, error: function(xhr, status, error){ console.log(error); } }); });
4. 修复后端接口的逻辑错误
/check_item_points/接口中,item是Pydantic模型实例,不能用字典取值方式,应从全局items字典获取数据:@app.post("/check_item_points/") def check_item_points(item: Item): global items item_id = item.name return items.get(item_id, 0), item.points/redeem_points/接口同时接收多个Pydantic模型,FastAPI无法解析;且存在赋值运算符错误和字典取值错误,合并模型并修正逻辑:class RedeemRequest(BaseModel): name: str item_name: str @app.post("/redeem_points/") def redeem_points(request: RedeemRequest): global users global items user_id = request.name item_id = request.item_name user_points = users.get(user_id, 0) item_cost = items.get(item_id, 0) if user_points >= item_cost: users[user_id] = user_points - item_cost return {"remaining_points": users[user_id], "redeemed_item": item_id} else: return {"error": "insufficient funds"}
5. 验证步骤
- 重启FastAPI服务,确保配置生效
- 用浏览器控制台或接口测试工具验证
/add_points/接口返回正常 - 运行前端HTML文件,点击按钮确认请求成功
内容的提问来源于stack exchange,提问作者Tommy Harris
相关产品推荐
相关产品推荐

