简体   繁体   中英

ajax request give 400 error with flask due bad json

Ok!! I'm building a flask web app, and I want to use Ajax to send some json data Here is my code!! for the HTML and js :

<!DOCTYPE html>
<html >
    <head>
        <meta charset="UTF-8">
        <title>Check your Grades</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <script src="{{ url_for('static', filename='js/bootstrap3-typeahead.min.js')}}"></script>
        <script type="text/javascript" src="{{ url_for('static', filename='js/index.js')}}"></script>
        <link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
    </head>
    <body>
        <link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
        <form id="predict-form" method="POST">
            <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
            <p> welcome to grade predictor app,</p>
            <p>Dear Plateform,</p>
            <p>je viens
                <label for="SCHOOL_RIGHT"> de </label>
                <input class="typeahead"  type="text" name="SCHOOL_RIGHT" id="SCHOOL_RIGHT" minlength="3" placeholder="(votre ecole de provenance)" data-provide="typeahead" autocomplete="off" required> et </p>
            <p>dans
                <label for="OPTION_RIGHT">l'option</label>
                <input class="typeahead"
                       name="OPTION_RIGHT" id="OPTION_RIGHT" data-provide="typeahead" placeholder="(choisissez votre option )" required>
            </p>
            <p>j'ai obtenu
                <label for="DIPPERC"></label>
                <input  type="number" name="DIPPERC" min="50" max="100" id="DIPPERC" placeholder="(Poucentage du
                                                                                                  diplome )" required> % à l\'exetat
            </p>
            <p>
                <button type="submit">
                    <svg version="1.1" class="send-icn" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100px" height="36px" viewBox="0 0 100 36" enable-background="new 0 0 100 36" xml:space="preserve">
                        <path d="M100,0L100,0 M23.8,7.1L100,0L40.9,36l-4.7-7.5L22,34.8l-4-11L0,30.5L16.4,8.7l5.4,15L23,7L23.8,7.1z M16.8,20.4l-1.5-4.3
                                 l-5.1,6.7L16.8,20.4z M34.4,25.4l-8.1-13.1L25,29.6L34.4,25.4z M35.2,13.2l8.1,13.1L70,9.9L35.2,13.2z" />
                    </svg>
                    <small>send</small>
                </button>
            </p>
        </form>
        <script >
            var csrf_token = "{{ csrf_token() }}";
            // this will send a token each time before a session started
            $.ajaxSetup({
                beforeSend: function(xhr, settings) {
                    if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
                        xhr.setRequestHeader("X-CSRFToken", csrf_token);
                    }
                }

            });
            //submit form data
            $("form#predict-form").submit(function(e){
                console.log("form submitted")
                e.preventDefault();
                var data = {
                }

                var Form = this;
                //Gathering the Data
                //and removing undefined keys(buttons)
                $.each(this.elements, function(i, v){
                    var input = $(v);
                    data[input.attr("name")] = input.val();
                    delete data["csrf_token"];
                    delete data["undefined"];
                });

                data["DIPPERC"] = data["DIPPERC"]/100.0
                //Form Validation goes here....
                //Save Form Data........
                $.ajax({
                    cache: false,
                    url : "{{url_for('predict')}}",
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    data : JSON.stringify(data),
                    success : function(callback){
                        //Where $(this) => context == FORM
                        console.log("data sucessfuly submitted")
                        console.log(JSON.parse(callback));
                    }
                    ,
                    error : function(){
                        console.log('erroor')
                    }
                });

            })
        </script>
    </body>
</html>

I've tried everything possible but still getting the 400 error! I've checked all related questions but nothing.

But my research shows that the 400 error can be caused by this according to :

  • from here it's said that :

The HTTP 400 Bad Request response status code indicates that the server could not understand the request due to invalid syntax. The client should not repeat this request without modification.

  • Csrf token missing this I've already added the token , and try to send the data to the route with csrf.exempt but nothing
  • ContentType and applicationType not set (already do it but nothing)
  • Already check in the official flask documentation they say : (from )
  • I'm sending correct json data
  • So what may cause this problem ??? here is my simple view function
@predictions.route('/predictions/predict/', methods=['GET', 'POST'])
def predict():
    if request.method == 'POST':
        print "hello----------------------"
        print request.method
        print request.get_json(force=True)
        return "done "

Note in my test when I send directly data via python to my route it works with this code :

def test_1_can_connect_post(self):
    """
Test API can create a  (POST request)
"""
    new_student = {
        'DIPPERC':0.60, 'SCHOOL_RIGHT':'itfm/bukavu', 'OPTION_RIGHT':'elec indust'
    }
    res = self.client().post('predictions/predict/', data=json.dumps(new_student), content_type='application/json')
    self.assertEqual(res.status_code, 201)

Ps: I'm sure that I'm missing a little thing but don't know what, maybe something wrong with ajax asynchronous .....

You don't need to convert your data into string: remove the JSON.stringify :

$.ajax({
    cache: false,
    url : "{{url_for('predict')}}",
    type: "POST",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    data : data,
    success : function(callback){
        //Where $(this) => context == FORM
              console.log("data sucessfuly submitted")
              console.log(JSON.parse(callback));
    },
    error : function(){
        console.log('erroor')
    }
});

With JSON.stringify you convert your data into a string, so you post a string, no JSON.

Ok , after 7 days of debugging i just found a solution for my problem : i do two things:

  1. from now and for my future web development i will stop using jquery and I'm sure that soon i will found good reason for that , so for my code i decide to use plain javascript and here is the code i use to send the request :

     var csrf_token = "{{ csrf_token() }}"; // this will send a token each time before a session started var form = document.getElementById("predict-form"); form.onsubmit = function (e) { // stop the regular form submission e.preventDefault(); // collect the form data while iterating over the inputs var formEntries = new FormData(form).entries(); var data = Object.assign(...Array.from(formEntries, ([x,y]) => ({[x]:y}))); delete data["csrf_token"]; data["DIPPERC"] = data["DIPPERC"]/100.0 console.log(data); // construct an HTTP request var xhr = new XMLHttpRequest(); xhr.open(form.method, form.action, true); xhr.setRequestHeader("X-CSRFToken", csrf_token); xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); // send the collected data as JSON xhr.send(JSON.stringify(data)); xhr.onloadend = function () { console.log('blallala ') }; };

    this was for the javascript part and I was sure that i was sending good json object to my server

  2. i went here at flask official documentation and found these 2 lines of attributes of flask request object

is_json : Indicates if this request is JSON or not. By default a request is considered to include JSON data if the mimetype is application/json or application/*+json.

and

data Contains the incoming request data as string in case it came with a mimetype Flask does not handle

and change my backend code to this :

@predictions.route('/predictions/predict/', methods=['GET', 'POST'])
def predict():
    """

    the main methode use to predict

    """
    if request.method == 'POST':
        print "hello----------------------"
        print request.is_json
        print request.data
        print '-----------------------------------------'
    return "done "

And VOILA!!!! get the 200 status code and the data as a python dict.

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