Flask and Ajax Post HTTP 400 Bad Request Error
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 (e.g. you used flask.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 }));};