简体   繁体   中英

Falcon cannot read request body

I am trying to read a simple request body with JSON data.

The request body:

[
{
    ...data
},
{
    ...data
}
]

When I try (In EventResource )

def on_post(self, req, resp):

    print(req.stream.read())

The following is logged into the console: b''

I have no clue what I am doing wrong or why it is not displaying my body data. Every example I see when doing this it actually logs the data instead of what I am getting.

Requirements.txt (might be some out of context, but I've added the full list just to be sure.)

astroid==1.5.3
bson==0.5.0
cffi==1.11.2
click==6.7
falcon==1.4.1
falcon-auth==1.1.0
falcon-jsonify==0.1.1
Flask==0.12.2
greenlet==0.4.12
gunicorn==19.7.1
isort==4.2.15
itsdangerous==0.24
Jinja2==2.10
lazy-object-proxy==1.3.1
MarkupSafe==1.0
mccabe==0.6.1
mimeparse==0.1.3
mongoengine==0.15.0
pycparser==2.18
PyJWT==1.5.3
pylint==1.7.4
pymongo==3.5.1
python-mimeparse==1.6.0
pytz==2017.3
readline==6.2.4.1
six==1.11.0
Werkzeug==0.12.2
wrapt==1.10.11

app.py

api = falcon.API(middleware=[
falcon_jsonify.Middleware(help_messages=settings.DEBUG)
])

routes.py

from app import api
from resources.event import EventResource
from resources.venue import VenueResource

# EventResources
api.add_route('/api/event', EventResource())
api.add_route('/api/event/{event_id}', EventResource())
api.add_route('/api/venue/{venue_id}/events', EventResource())

# VenueResources
api.add_route('/api/venue', VenueResource())
api.add_route('/api/venue/{venue_id}', VenueResource())
api.add_route('/api/event/{event_id}/venue', VenueResource())

I run my project with gunicorn routes:api --reload

Example POST request (that logs the b'' ):

curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://localhost:8000/api/event

The only thing I added as a header is Content-Type / application/json

I've read through this but it didn't help me.

The behavior happens because your

falcon_jsonify.Middleware(help_messages=settings.DEBUG)

The stream is already read by it. You need to use req.json in that case. If you remove the middleware then req.stream.read() will return the value correctly. If you look at the middleware's process_request method

def process_request(self, req, resp):
    if not req.content_length:
        return

    body = req.stream.read()
    req.json = {}
    self.req = req
    req.get_json = self.get_json

    try:
        req.json = json.loads(body.decode('utf-8'))

    except ValueError:
        self.bad_request("Malformed JSON", "Syntax error")

    except UnicodeDecodeError:
        self.bad_request("Invalid encoding", "Could not decode as UTF-8")

You can see the that middleware reads the body and then spits out the same in req.json as a parsed object. But the original body is not saved anywhere else. Once a request stream is read, you have emptied its buffer and won't get the data again. Hence you get b''

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