简体   繁体   中英

Flask and Ajax Post HTTP 400 Bad Request Error

I am writing a small flask based site and I would like to send data from the client to the server using Ajax. Until now I have only used Ajax requests to retrieve data from the server. This time I would like to submit data via POST request.

This is the receiver on the flask side, I reduced it to barely log a message to avoid any unnecessary errors within the implementation of this route:

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

When submitting the ajax request, flask gives me a 400 error

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

I can also see this in the web developer console in the browser

Why is flask not calling submit_handler with the supplied data in the request?

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

If you are using the Flask-WTF CSRF protection you'll need to either exempt your view or include the CSRF token in your AJAX POST request too.

Exempting is done with a decorator:

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

To include the token with AJAX requests, interpolate the token into the page somewhere; in a <meta> header or in generated JavaScript, then set a X-CSRFToken header. When using jQuery, use the ajaxSetup hook .

Example using a meta tag (from the Flask-WTF CSRF documentation):

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

and in your JS code somewhere:

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)
        }
    }
})

Your handler doesn't actually post JSON data yet; it is still a regular url-encoded POST (the data will end up in request.form on the Flask side); you'd have to set the AJAX content type to application/json and use JSON.stringify() to actually submit JSON:

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

and now the data can be accessed as a Python structure with the request.get_json() method .

The dataType: "json", parameter to $.ajax is only needed when your view returns JSON (eg you usedflask.json.jsonify() to produce a JSON response). It lets jQuery know how to process the response.

Can you try like this

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

Before that, In your code returns dict object. That is not correct. It returns json like

@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'})

A similar solution that does not require 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
    }));
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM