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

使用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. 验证步骤

  1. 重启FastAPI服务,确保配置生效
  2. 用浏览器控制台或接口测试工具验证/add_points/接口返回正常
  3. 运行前端HTML文件,点击按钮确认请求成功

内容的提问来源于stack exchange,提问作者Tommy Harris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 04:35:19