Search code examples
pythonjsonajaxtornado

Python Tornado request JSON


My application accepts data from POST method which I am running through JQuery's AJAX request. I am sending JSON formatted data, but in handler as I accept request and access the data it turns out to be byte string type.

I am using my_body = self.request.body method.

For example, if I am sending {"drzava":"rs","kategorija":"general"} received data looks like b'drzava=rs&kategorija=general'.

Problem is, afterwards I can't use tornado.escape.json_decode(), to make it dictionary. I keep getting the following error:

Traceback (most recent call last):
  File "/home/stefan/.local/lib/python3.6/site-packages/tornado/web.py", line 1697, in _execute
    result = method(*self.path_args, **self.path_kwargs)
  File "main.py", line 164, in post
    telo_json = tornado.escape.json_decode(telo)
  File "/home/stefan/.local/lib/python3.6/site-packages/tornado/escape.py", line 83, in json_decode
    return json.loads(to_basestring(value))
  File "/usr/lib/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.6/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

I will post the code, if needed.


Solution

  • UPDATE: Firstly, there was a typo in my .js file, so AJAX requests weren't being sent. Secondly, Tornado was detecting default POST method (not the AJAX's one), so you have to manually override it by saying something like e.preventDefault(); where e is parameter of anonymous function in JQUERY's action. On the other side, in Tornado, result of self.request.body is something like b'{"country":"rs","category":"sports"}' which can be transformed to dictionary using tornado.escape.json_decode(). Many thanks to @Ionut Ticus for constructive suggestions.

    So, after bit of investigating and reading docs, I found the following:

    HTTPServerRequest.body is now always a byte string (previously the default empty body would be aunicode string on python 3)

    This is written it Tornado's official documentation. Tornado Documentation Release 6.0.4 page 183

    Hovewer, I found a way around it.

    argumenti = self.request.arguments
    drzava_val = argumenti['drzava'][0].decode("utf-8")
    kategorija_val =  argumenti['kategorija'][0].decode("utf-8")
    
    data = {
                'drzava': drzava_val,
                'kategorija': kategorija_val
            }