Flask和Ajax发布HTTP 400错误

22 投票
3 回答
12776 浏览
提问于 2025-04-18 01:17

我正在写一个基于Flask的小网站,想通过Ajax把数据从客户端发送到服务器。之前我只用Ajax请求从服务器获取数据。这次我想通过POST请求提交数据。

这是Flask端的接收代码,我把它简化到只记录一条消息,以避免在这个路由的实现中出现不必要的错误:

@app.route("/json_submit", methods=["POST"])
def submit_handler():
    # a = request.get_json(force=True)
    app.logger.log("json_submit")
    return {}

当我提交Ajax请求时,Flask给了我一个400错误

127.0.0.1 - - [03/Apr/2014 09:18:50] "POST /json_submit HTTP/1.1" 400 -

我在浏览器的开发者控制台也能看到这个错误

为什么Flask没有用请求中提供的数据调用submit_handler呢?

 var request = $.ajax({
    url: "/json_submit",
    type: "POST",
    data: {
      id: id, 
      known: is_known
    },  
    dataType: "json",
  })  
   .done( function (request) {
  })

3 个回答

0

这是一个类似的解决方案,不需要使用jQuery。

<meta name="csrf-token" content="{{ csrf_token() }}">

var beforeSend = function(xhr) {
    var csrf_token = document.querySelector('meta[name=csrf-token]').content;
    xhr.setRequestHeader("X-CSRFToken", csrf_token);
};

function fooFunction() {
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/json-submit");
    xhr.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            // Do what you want with this.responseText
        }
    };
    beforeSend(xhr);
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xhr.send(JSON.stringify({
        'id': id, 'known': is_known
    }));
};
2

你可以试试这样做

var request = $.ajax({
    url: "/json_submit",
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify({
      id: id, 
      known: is_known
    }),  
    dataType: "json",
  })  
   .done( function (request) {
 })

在此之前,你的代码返回的是一个字典对象。这是不对的。它应该返回的是像这样的json格式

@app.route("/json_submit", methods=["POST"])
def submit_handler():
    # a = request.get_json(force=True)
    app.logger.log("json_submit")
    return flask.jsonify({'msg': 'success'})
32

如果你在使用 Flask-WTF 的 CSRF 保护,你需要么让你的视图不受保护,或者在你的 AJAX POST 请求中也包含 CSRF 令牌。

让视图不受保护的方法是使用一个装饰器:

@csrf.exempt
@app.route("/json_submit", methods=["POST"])
def submit_handler():
    # a = request.get_json(force=True)
    app.logger.log("json_submit")
    return {}

如果要在 AJAX 请求中包含令牌,可以把令牌放在页面的某个地方,比如在一个 <meta> 标签里,或者在生成的 JavaScript 代码中,然后设置一个 X-CSRFToken 的请求头。如果你使用 jQuery,可以用 ajaxSetup 方法

下面是一个使用 meta 标签的例子(来自 Flask-WTF CSRF 文档):

<meta name="csrf-token" content="{{ csrf_token() }}">

然后在你的 JavaScript 代码中的某个地方:

var csrftoken = $('meta[name=csrf-token]').attr('content')

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken)
        }
    }
})

你的处理函数其实还没有发送 JSON 数据;它仍然是一个普通的 URL 编码的 POST 请求(数据会在 Flask 端的 request.form 中找到);你需要把 AJAX 的内容类型设置为 application/json,并使用 JSON.stringify() 来真正提交 JSON 数据:

var request = $.ajax({
   url: "/json_submit",
   type: "POST",
   contentType: "application/json",
   data: JSON.stringify({
     id: id, 
     known: is_known
   }),  
})  
  .done( function (request) {
})

现在数据可以通过 request.get_json() 方法 作为 Python 结构来访问。

$.ajax 中的 dataType: "json", 参数只有在你的视图 返回 JSON 时才需要(例如,你使用了 flask.json.jsonify() 来生成 JSON 响应)。这个参数告诉 jQuery 如何处理响应。

撰写回答