Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No response with POST request and Content-Type "application/json" in flask

I'm having problems with a Flask view that should return a response with content-type "application/json" in response to a POST request. Specifically, if I do:

curl -v -d 'foo=bar' http://example.org/jsonpost

to this view:

@app.route('/jsonpost', methods=['GET', 'POST'])
def json_post():
    resp = make_response('{"test": "ok"}')
    resp.headers['Content-Type'] = "application/json"
    return resp

I get some sort of connection reset:

* About to connect() to example.org port 80 (#0)
*   Trying xxx.xxx.xxx.xxx... connected
* Connected to example.org (xxx.xxx.xxx.xxx) port 80 (#0)
> POST /routing/jsonpost HTTP/1.1
> User-Agent: curl/7.19.7 (i486-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: example.org
> Accept: */*
> Content-Length: 7
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< Server: nginx/1.2.4
< Date: Thu, 27 Dec 2012 14:07:59 GMT
< Content-Type: application/json
< Content-Length: 14
< Connection: keep-alive
< Set-Cookie: session="..."; Path=/; HttpOnly
< Cache-Control: public
<
* transfer closed with 14 bytes remaining to read
* Closing connection #0
curl: (18) transfer closed with 14 bytes remaining to read

If instead I do:

curl -d 'foo=bar' http://example.org/htmlpost

to:

@app.route('/htmlpost', methods=['GET', 'POST'])
def html_post():
    resp = make_response('{"test": "ok"}')
    resp.headers['Content-Type'] = "text/html"
    return resp

I get the expected the full response (200-ok)

{"test": "ok"}

By the way, if I send a GET request to the same JSON route:

curl http://example.org/jsonpost

I also get the expected response.. Any ideas?

like image 942
Marcoq Avatar asked Dec 11 '22 19:12

Marcoq


1 Answers

Thanks to Audrius's comments I tracked a possible source of the problem to the interaction between uWSGI and nginx: apparently, if you receive POST data in a request you must read it before returning a response.

This, for example, fixes my issue.

@app.route('/jsonpost', methods=['GET', 'POST'])
def json_post():
    if request.method == 'POST':
        dummy = request.form
    resp = make_response('{"test": "ok"}')
    resp.headers['Content-Type'] = "application/json"
    return resp

A different solution involves passing --post-buffering 1 to uWSGI as described by uWSGI's author Roberto De Ioris.

I still don't understand why the problem does not present itself with Content-Type set to "text/html"

like image 123
Marcoq Avatar answered May 03 '23 19:05

Marcoq