user94628
user94628

Reputation: 3721

Tornado cannot read json ajax requests

Using ajax I'm trying to send data to my Tornado server, this is my JQuery:

$("#addTask").submit(function(e){
    e.preventDefault();
    var add = $('#addProject').val();
    var added={projectAdded:add};
      $.post("/task",
              JSON.stringify(added),
        function(data){
            window.location.reload(true);
              });
    });

The value of $('#addProject').val(); is from an input text field:

$('<div class="input-group col-sm-7"><input type="text" form="task" class="form-control" id="addProject" name="projectAdd" value="" placeholder="New tag">
<button type="submit" name="addTag" value="addTag" form="task" id="addTask"></button>  </div>').appendTo('#proj');

In my Tornado server I have:

 class TaskAddHandler(BaseHandler):
    def post(self):
        addProj = json.loads(self.request.body)       
        print 'NEW TASK', addProj

But this gives me the error: raise ValueError("No JSON object could be decoded") ValueError: No JSON object could be decoded, instead of the value of the input text field.

Upvotes: 1

Views: 2405

Answers (2)

scharfmn
scharfmn

Reputation: 3661

The data is in self.request.arguments. Also, you need to return valid json to the client.

class AjaxHandler(tornado.web.RequestHandler):

    def post(self):
        my_data = self.request.arguments['test_data']
        # do something with my_data 
        self.write(json.dumps({'status': 'ok'}))
        self.finish()

The self.write(json.dumps({'status': 'ok'})) response from the handler is necessary to complete the transaction with the client: any valid json will do; it doesn't matter what the content is. (See this answer if the client does not seem to get the json back.)

It could also be that _xsrf_cookies: True in your settings within run_server.py. If that's the case, the ajax request itself will be blocked by Tornado (and you'll see 400 Bad Request on the console).

To deal with that, "the XSRF token may... be passed via an HTTP header named X-XSRFToken," says the doc. Set the cookie via the get of whatever page contains, or calls, that ajax logic, via self.xsrf_token. Doing so, the doc says, "is enough to set the cookie as a side effect":

class PageHandler(tornado.web.RequestHandler):
    def get(self):
        self.xsrf_token
        self.render('page.html')

Can then pick up the cookie in the client (here via the jQuery $.cookie plugin):

var token = $.cookie('_xsrf');

Embed the token as a custom headers parameter in the call:

$.ajax({
    url: '/task',
    headers: {'X-XSRFToken' : token },
    data: {'test_string': 'test success'},
    dataType: "JSON",
    type: "POST",
    success: function ( data , status_text, jqXHR) {
        alert('ajax success')
    },
    error: function ( data , status_text, jqXHR ) {
        alert('ajax fail')
    },
});

Alternately, you can also put it as one of the fields in data. (And if you are ajaxing a JavaScript object as one of your fields, you should JSON.stringify it in order to get a nicely-structured dict back on the server side):

var packet = {"_xsrf": $.cookie("_xsrf"), "test_string": "test success", "js_obj": JSON.stringify(js_obj)}; 

$.ajax({
    url: '/task',
    data: packet,
    dataType: "JSON",
    type: "POST",
    success: function ( data , status_text, jqXHR) {
        alert('ajax success')
    },
    error: function ( data , status_text, jqXHR ) {
        alert('ajax fail')
    },
});

There is also an example of managing _xsrf_cookies in the sample chat app referred to in the doc.

Upvotes: 4

Geoff Genz
Geoff Genz

Reputation: 2109

I think you need to send a JSON string as your data, not the object. Try JSON.stringify({projectAdded:add}) instead of just the object.

Upvotes: 0

Related Questions