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

使用AJAX向Flask提交POST请求遇405错误,疑为CORS问题?

问题分析与修复方案

核心问题:jQuery AJAX请求URL获取错误

你的JS代码中,获取请求地址的方式存在明显错误:

var actionUrl = form.attr('http://127.0.0.1:5000/numberapi');

form.attr()方法用于读取表单的属性值(如action、method这类预设属性),不是直接传入完整URL。这会导致actionUrl值为undefined,AJAX请求默认发送到当前页面URL,而该URL对应的Flask路由大概率不支持POST方法,最终触发405错误。

修复步骤1:修正AJAX请求URL

两种可行方案:

  • 方案一:若表单已设置action="http://127.0.0.1:5000/numberapi",修改为:
var actionUrl = form.attr('action');
  • 方案二:直接指定URL字符串:
var actionUrl = "http://127.0.0.1:5000/numberapi";

额外需要修复的Flask后端问题

即便解决了405错误,你的后端代码仍存在多个功能异常点:

  1. 表单数据解析错误
    前端用form.serialize()发送的是application/x-www-form-urlencoded格式数据,但后端却用json.loads(bytes.decode(request.data))解析JSON,必然导致解析失败。应改用request.form获取表单数据:
birth_year = request.form.get('birth_year', type=int)
color = request.form.get('color', '').lower()
  1. CSRF验证问题
    form.validate_on_submit()依赖CSRF Token验证,AJAX提交时需携带Token。可通过两种方式实现:
  • 方式一:在表单数据后拼接Token:
$.ajax({
    type: "POST",
    url: actionUrl,
    data: form.serialize() + "&csrf_token=" + "{{ csrf_token() }}",
    success: function(data) {
        alert(JSON.stringify(data));
    }
});
  • 方式二:通过请求头传递Token:
$.ajax({
    type: "POST",
    url: actionUrl,
    headers: {
        "X-CSRFToken": "{{ csrf_token() }}"
    },
    data: form.serialize(),
    success: function(data) {
        alert(JSON.stringify(data));
    }
});
  1. 响应格式不规范
    后端直接返回return [year_fact,number_fact]不符合HTTP响应规范,需用jsonify包装:
return jsonify(year_fact=year_fact, number_fact=number_fact)
  1. 错误分支未正确返回
    错误处理分支中定义了retrieved变量但未返回,会导致代码走到最后返回"csrf validation did not pass",需补充返回逻辑:
if color not in valid_colors:
    print("error of color")
    form.color.errors = ["Please pick a valid colour"]
    return jsonify(errors=form.color.errors)  # 补充返回

修正后的完整代码示例

前端jQuery代码

$("#lucky-form").submit(function(e) {
    e.preventDefault();
    console.log("running this form");

    var form = $(this);
    var actionUrl = "http://127.0.0.1:5000/numberapi";

    $.ajax({
        type: "POST",
        url: actionUrl,
        data: form.serialize() + "&csrf_token=" + "{{ csrf_token() }}",
        success: function(data) {
            alert(JSON.stringify(data));
        },
        error: function(xhr, status, error) {
            console.error("请求错误:", error);
            alert("请求失败:" + xhr.responseText);
        }
    });
});

后端Flask代码

from flask import Flask, request, jsonify
from flask_wtf import FlaskForm
from wtforms import IntegerField, StringField
from wtforms.validators import DataRequired
from flask_cors import cross_origin

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-custom-secret-key'  # 必填,用于CSRF验证

valid_colors = ['red', 'blue', 'green', 'yellow']

class LuckyNumberForm(FlaskForm):
    birth_year = IntegerField('birth_year', validators=[DataRequired()])
    color = StringField('color', validators=[DataRequired()])

def valid_dob(birth_year):
    return 1900 <= birth_year <= 2000

def get_dob_fact(birth_year):
    return {"year": birth_year, "fact": f"年份{birth_year}有专属小秘密!"}

def get_number_fact():
    import random
    num = random.randint(1, 100)
    return {"number": num, "fact": f"数字{num}是你的幸运数!"}

@app.route("/numberapi", methods=['GET','POST'])
@cross_origin()
def get_lucky_number():
    form = LuckyNumberForm()
    birth_year = request.form.get('birth_year', type=int)
    color = request.form.get('color', '').lower()

    if form.validate_on_submit():
        print("validated!")
        if color not in valid_colors:
            print("error of color")
            form.color.errors = ["请选择有效的颜色"]
            return jsonify(errors=form.color.errors)
        
        elif not valid_dob(birth_year):
            print("error of dob")
            form.birth_year.errors = ["请选择1900-2000之间的出生年份"]
            return jsonify(errors=form.birth_year.errors)
        else:
            year_fact = get_dob_fact(birth_year)
            number_fact = get_number_fact()
            print(year_fact)
            print(number_fact)
            return jsonify(year_fact=year_fact, number_fact=number_fact)

    return jsonify(error="CSRF验证未通过")

if __name__ == "__main__":
    app.run(debug=True)

内容的提问来源于stack exchange,提问作者Sean.realitytester

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 12:44:51