通过Flask后端将来自JavaScript前端的HTML表单数据发送到MySQL数据库时出错

前端开发 2026-07-09

在尝试通过Flask后端,将带有JS前端的HTML表单数据发送到MySQL数据库时,我在浏览器的开发者工具控制台遇到了错误“400 (BAD REQUEST)”。

HTML表单:

<form id="form" method="POST">
        <label> Date ID </label>
        <input type="text" id="dateID" name="dateID">
        <br>
        <label> Day of the Week </label>
        <input type="text" id="week_day" name="week_day">
        <br>
        <label> Day </label>
        <input type="date" id="day" name="day">
        <br>
        <label> Rate  </label>
        <input type="text" id="rate" name="rate">
        <br>
        <input type="submit">
    </form>

JS前端:

const form = document.getElementById("form")

document.getElementById('form').addEventListener('submit', function(e) {
    e.preventDefault()

    const dateID = document.getElementById('dateID').value
    const weekDay = document.getElementById('week_day').value
    const day = document.getElementById('day').value
    const rate = document.getElementById('rate').value

    const formData = new FormData(form)
    //console.log(formData.values)
    const url = "http://localhost:6969/add-data"

    fetch(url, {
       method: "POST",
       headers: {
            'Content-Type':'application/json',
            'Accept': 'application/json'
       },
       //body: JSON.stringify(formData)
       body: formData
    })

    // const result = response.json()
    // console.log("Success:", result)
})

Flask后端:

@app.route("/add-data", methods=['POST'])
@cross_origin()
def add():
    data=request.json
    dateID=data.get('dateID')
    week_day=data.get('week_day')
    day=data.get('day')
    rate=data.get('rate')
    cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
    sql_query="INSERT INTO years_2016_2025 (dateID, week_day, day, rate) VALUES (%s, %s, %s, %s)"
    cursor.execute(sql_query, (dateID, week_day, day, rate))
    mysql.connection().commit()
    cursor.close()
    return jsonify({"message": "Data saved successfully!"}, 201)

我已经尝试将表单数据输出到控制台,但结果为null;开发者工具的网络响应错误信息显示:“浏览器(或代理)发送了服务器无法理解的请求。”

解决方案

如果你想以 JSON 发送,那么你不能使用 formData,但

body: JSON.stringify({ dateID: dateID, week_day: weekDay, day: day, rate: rate }),

你可以在Mozilla文档中找到关于 fetch 的更多信息:Fetch API的使用


你也可以使用

body: JSON.stringify(Object.fromEntries(formData)),

就像在这个问题的回答中
javascript - How to convert FormData (HTML5 object) to JSON - Stack Overflow


如果你想要发送带有代码 201 的响应,那么它必须位于 jsonify 之外
它必须创建一个元组 data, code

return jsonify({"message": "Data saved successfully!"}), 201

Flask文档:关于响应


最小可运行的代码(不含数据库)单文件版,方便大家直接复制并测试。

from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin
from waitress import serve

PORT = 6969

html = """
<!DOCTYPE html>

<head>
<meta charset="utf-8">
</head>

<body>
<form id="form" method="POST">
    <label> Date ID </label>
    <input type="text" id="dateID" name="dateID">
    <br>
    <label> Day of the Week </label>
    <input type="text" id="week_day" name="week_day">
    <br>
    <label> Day </label>
    <input type="date" id="day" name="day">
    <br>
    <label> Rate  </label>
    <input type="text" id="rate" name="rate">
    <br>
    <input id="submit" type="submit">
</form>

<div id="message"></div>

<script>
const form = document.getElementById("form");
const message = document.getElementById("message");

form.addEventListener('submit', function(event) {
  event.preventDefault();

  const dateID = document.getElementById('dateID').value;
  const weekDay = document.getElementById('week_day').value;
  const day = document.getElementById('day').value;
  const rate = document.getElementById('rate').value;

  const formData = new FormData(form);

  //const url = "http://localhost:6969/add-data";
  const url = "/add-data";  // you can use URL without domain and port

  fetch(url, {
    method: "POST",
    headers: {
      'Content-Type':'application/json',
      'Accept': 'application/json'
    },
    //body: formData  // wrong: form body
    //body: JSON.stringify(formData)  // wrong: empty body
    body: JSON.stringify(Object.fromEntries(formData))  // works
    //body: JSON.stringify({dateID: dateID, week_day: weekDay, day: day, rate: rate}) // works
  })
  .then(response => response.json())   // TODO: use `if(!response.ok)` to catch errors 40x, 50x
  .then(data => {
    console.log("Success:", data.message);
    message.innerHTML = data.message;
  })
  .catch(error => {
    console.error("Error:", error);
    message.innerHTML = error;
  });
})
</script>
</body>

</html>"""

app = Flask(__name__)
CORS(app)
app.secret_key = ""


@app.route("/")
@cross_origin()
def index():
    return html


@app.route("/add-data", methods=["POST"])
@cross_origin()
def add():
    data = request.json
    dateID = data.get("dateID")
    week_day = data.get("week_day")
    day = data.get("day")
    rate = data.get("rate")

    print(f"{data=}")

    # cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
    # sql_query="INSERT INTO years_2016_2025 (dateID, week_day, day, rate) VALUES (%s, %s, %s, %s)"
    # cursor.execute(sql_query, (dateID, week_day, day, rate))
    # mysql.connection().commit()
    # cursor.close()

    return jsonify({"message": "Data saved successfully!"}), 201


if __name__ == "__main__":
    print(f"Running http://localhost:{PORT}")
    # app.run("localhost", port=PORT, debug=True)
    serve(app, host="0.0.0.0", port=PORT)

同时我添加了用于数据库的代码 sqlite(不需要安装服务器),
所以大家仍然可以直接复制并运行。
它会自动创建数据库文件。

我还添加了一个页面,用于显示数据库中所有数据的表。
它使用 render_template_string{% for ... %}
表格的链接在表单上方。

from flask import Flask, request, jsonify, render_template_string
from flask_cors import CORS, cross_origin
from waitress import serve
import sqlite3

PORT = 6969

html = """
<!DOCTYPE html>

<head>
<meta charset="utf-8">
</head>

<body>
<a href="/all">Table</a>
<hr>
<form id="form" method="POST">
    <label> Date ID </label>
    <input type="text" id="dateID" name="dateID">
    <br>
    <label> Day of the Week </label>
    <input type="text" id="week_day" name="week_day">
    <br>
    <label> Day </label>
    <input type="date" id="day" name="day">
    <br>
    <label> Rate  </label>
    <input type="text" id="rate" name="rate">
    <br>
    <input id="submit" type="submit">
</form>

<div id="message"></div>

<script>
const form = document.getElementById("form");
const message = document.getElementById("message");

form.addEventListener('submit', function(event) {
  event.preventDefault();

  const dateID = document.getElementById('dateID').value;
  const weekDay = document.getElementById('week_day').value;
  const day = document.getElementById('day').value;
  const rate = document.getElementById('rate').value;

  const formData = new FormData(form);

  //const url = "http://localhost:6969/add-data";
  const url = "/add-data";  // you can use URL without domain and port

  fetch(url, {
    method: "POST",
    headers: {
      'Content-Type':'application/json',
      'Accept': 'application/json'
    },
    //body: formData  // wrong: form body
    //body: JSON.stringify(formData)  // wrong: empty body
    body: JSON.stringify(Object.fromEntries(formData))  // works
    //body: JSON.stringify({dateID: dateID, week_day: weekDay, day: day, rate: rate}) // works
  })
  .then(response => response.json())   // TODO: use `if(!response.ok)` to catch errors 40x, 50x
  .then(data => {
    console.log("Success:", data.message);
    message.innerHTML = data.message;
  })
  .catch(error => {
    console.error("Error:", error);
    message.innerHTML = error;
  });
})
</script>
</body>

</html>"""

app = Flask(__name__)
CORS(app)
app.secret_key = ""


@app.route("/")
@cross_origin()
def index():
    return html


@app.route("/add-data", methods=["POST"])
@cross_origin()
def add():
    data = request.json
    dateID = data.get("dateID")
    week_day = data.get("week_day")
    day = data.get("day")
    rate = data.get("rate")

    print(f"{data=}")

    # mysql_insert(dateID, week_day, day, rate)
    sqlite_insert(dateID, week_day, day, rate)

    return jsonify({"message": "Data saved successfully!"}), 201


@app.route("/all")
def show_all():
    data = sqlite_select_all()
    return render_template_string(
        """
    <style>
    td {border: 1px solid black; padding: 5px 15px;}
    </style>

    <a href="/">Main</a>
    <hr>

    <table>
    <tr><th>ID</th><th>Date ID</th><th>WeekDay</th><th>Day</th><th>Rate</th></tr>
    {% for row in data %}
    <tr>{% for item in row %}<td>{{ item }}</td>{% endfor %}<tr>
    {% endfor %}
    </table>
    """,
        data=data,
    )


def mysql_insert(dateID, week_day, day, rate):

    cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)

    sql_query = "INSERT INTO years_2016_2025 (dateID, week_day, day, rate) VALUES (%s, %s, %s, %s)"
    cursor.execute(sql_query, (dateID, week_day, day, rate))

    mysql.connection().commit()
    cursor.close()


def sqlite_create():
    # import sqlite3

    query = """
    CREATE TABLE IF NOT EXISTS years_2016_2025 (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        dateID TEXT,
        week_day TEXT,
        day TEXT,
        rate TEXT
    )
    """

    conn = sqlite3.connect("database.db")
    cursor = conn.cursor()

    cursor.execute(query)

    conn.commit()
    conn.close()

    print("Database created")

    result = sqlite_select_all()
    if not result:
        print("empty database ... adding example rows")
        sqlite_insert("today", "Sunday", "2026-05-31", "-1_000_000")
        sqlite_insert("yesterday", "Saturday", "2026-05-30", "+1_000_000")
    else:
        print("database not empty")


def sqlite_insert(dateID, week_day, day, rate):

    query = (
        "INSERT INTO years_2016_2025 (dateID, week_day, day, rate) VALUES (?, ?, ?, ?)"
    )

    conn = sqlite3.connect("database.db")
    cursor = conn.cursor()

    result = cursor.execute(query, (dateID, week_day, day, rate))
    result = result.fetchall()

    conn.commit()
    conn.close()

    return result


def sqlite_select_all():
    query = "SELECT * FROM years_2016_2025"

    conn = sqlite3.connect("database.db")
    cursor = conn.cursor()

    result = cursor.execute(query)
    result = result.fetchall()

    conn.commit()
    conn.close()

    return result


if __name__ == "__main__":
    sqlite_create()  # you can remove after first execution (but if you keep it then it will not delete previous data)
    print(f"Running http://localhost:{PORT}")
    # app.run("localhost", port=PORT, debug=True)
    serve(app, host="0.0.0.0", port=PORT)

在此输入图片描述


在此输入图片描述

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章