Flask 400 错误排查:正确使用 FormData 发送 POST 请求

flask 接收 xmlhttprequest 的 post 数据时返回 400 错误,通常是因为前端未按 `application/x-www-form-urlencoded` 格式提交数据,而 flask 的 `request.form` 仅解析该格式;解决方案是改用 `formdata` 对象封装数据并发送。

在 Flask 中,request.form 是一个类字典对象,专门用于解析标准表单编码(即 Content-Type: application/x-www-form-urlencoded)的请求体。当你直接调用 xmlhttp.send("json=" + encodeURI(...)) 时,虽然字符串结构看似符合表单格式,但 默认情况下 XMLHttpRequest 并未设置正确的 Content-Type 头,导致 Flask 无法识别并解析请求体,进而抛出 400 Bad Request 错误(常见于访问 request.form["json"] 时触发 BadRequestKeyError 或空值校验失败)。

✅ 正确做法是使用 FormData 对象 —— 它会自动设置 Content-Type: multipart/form-data(或在无文件时退化为 application/x-www-form-urlencoded),并确保键值对被 Flask 正确捕获:

function del(e) {
    const getXmlhttp = new XMLHttpRequest();
    getXmlhttp.onload = function () {
        try {
            const json = JSON.parse(this.responseText);
            const newJson = json.filter(item => item.name !== e.parentElement.childNodes[2].textContent);

            const postXmlhttp = new XMLHttpRequest();
            postXmlhttp.open("POST", "/orders");
            postXmlhttp.onreadystatechange = function () {
                if (postXmlhttp.readyState === 4 && postXmlhttp.status === 200) {
                    // 可选:刷新页面或更新 UI
                    location.reload();
                }
            };

            const formData = new FormData(); // ✅ 创建 FormData 实例
            formData.append("json", JSON.stringify(newJson)); // ✅ 自动编码,无需手动 encodeURI

            postXmlhttp.send(formData); // ✅ 自动设置合适 Content-Type
        } catch (err) {
            console.error("JSON 解析或请求处理失败:", err);
        }
    };
    getXmlhttp.open("GET", "/json");
    getXmlhttp.send();
}

⚠️ 同时,后端 Flask 路由也需增强健壮性,避免因缺失字段或空值引发异常:

@app.route("/orders", methods=["POST", "GET"])
def order():
    global orders
    if request.method == "GET":
        return render_template("orders.html", orders=orders)

    # 安全地获取 form 数据
    json_str = request.form.get("json")
    if not json_str:
        return "Missing 'json' field", 400

    try:
        orders = json.loads(unquote(json_str))
        newOrder(orders)  # 假设 newOrder 接收解析后的列表
        return "", 204  # No Content 表示成功处理
    except json.JSONDecodeError:
        return "Invalid JSON in 'json' field", 400
    except Exception as e:
        return f"Server error: {str(e)}", 500

? 关键要点总结:

  • ❌ 不要手动拼接查询字符串(如 "json=" + ...)并用 send() 发送纯文本;
  • ✅ 必须使用 FormData 封装键值对,让浏览器自动处理编码与头部设置;
  • ✅ 后端务必使用 request.form.get(key) 替代 request.form[key],防止 KeyError;
  • ✅ 始终校验输入、捕获 JSON 解析异常,并返回明确的 HTTP 状态码便于前端调试。

遵循以上规范,即可彻底解决 Flask + XMLHttpRequest 场景下的 400 错误问题。