web-dev-qa-db-ja.com

Python Falcon-get POST data

プロジェクトでfalconパッケージを使用しようとしています。問題は、HTTPポストリクエストからボディデータを取得する方法を見つけられなかったことです。

例のコードを使用しましたが、req.stream.read()は期待どおりJSONを返しません。

コードは次のとおりです。

raw_json = req.stream.read()
result.json(raw_json, encoding='utf-8')
resp.body = json.dumps(result_json, encoding='utf-8')

POSTデータを取得するには?

助けてくれてありがとう

7
Gomi

問題を少し掘り下げると、次のようになりました githubのリンクされた問題 。少なくともバージョン0.3のfalconフレームワークで、Python 2で動作する場合、適切にエスケープされている場合、文字列として 'POSTされた'データは解析されませんでした。 POSTリクエストおよび送信する形式は、単純なテキストとして送信する場合、ヘッダー情報Content-Type:application/jsonを使用する場合、またはHTMLフォームを使用します。

正確な問題は質問から明らかではありませんが、bounded_streamの代わりにstreamの代わりに:

raw_json = req.bounded_stream.read()
result.json(raw_json, encoding='utf-8')
resp.body = json.dumps(result_json, encoding='utf-8')

公式ドキュメントについては、bounded_streamここで、Content-Lengthが未定義または0などの不確実な条件、またはヘッダー情報が完全に欠落している場合。

bounded_streamは、公式の falcon documentation で次のように記述されています。

さまざまなWSGIサーバーによって使用されるネイティブ入力オブジェクト間の特定の違いを正規化する、ストリームの周りのファイルのようなラッパー。特に、bounded_streamは、予想される本文のContent-Lengthを認識しており、クライアントがサーバーへのデータ送信中にストールしないと仮定して、範囲外の読み取りでブロックすることはありません。

Falconは、クライアントからデータを受信するWSGIラッパーによって渡されるバッファオブジェクトとしてHTTPリクエストデータを受信します。パフォーマンス上の理由により、データの上で適切な解析を実行してより使いやすいデータ構造に変換することはできません。

6
Shubham Mishra

探しているフィールドの名前はやや紛らわしいですが、 req.media です:

要求ストリームの逆シリアル化された形式を返します。呼び出されると、Content-Typeヘッダーとfalcon.RequestOptionsで構成されたメディアタイプハンドラーを使用して、要求ストリームの逆シリアル化を試みます。

リクエストがJSONの場合、req.mediaにはpython dict。

3
mb21

falcon 2で、jsonタイプを使用する場合は、- req.media

例えば:

import falcon
from json import dumps

class Resource(object):
    def on_post(self, req, resp, **kwargs):
        result = req.media
        # do your job
        resp.body = dumps(result)


api = falcon.API()

api.add_route('/test', Resource())
2
mosi_kha

Ryan(およびPrateek Jain)の回答に感謝します。

解決策は、単にapp.req_options.auto_parse_form_urlencoded=True。例えば:

import falcon

class ThingsResource(object):
    def on_post(self, req, resp):
        value = req.get_param("value", required=True)
        #do something with value

app = falcon.API()
app.req_options.auto_parse_form_urlencoded=True

things = ThingsResource()

app.add_route('/things', things)
2
Zezombye

これまで...私にとっては、bounded_stream.read()とstream.read()は両方とも、投稿されたデータをstr型として取得します。これまでのところ、この問題を回避する方法は1つしかありません。

def on_post(self, req, resp):
    posted_data = json.loads(req.stream.read())
    print(str(type(posted_data)))
    print(posted_data)

投稿されたデータを受け取ったら、json dictに文字列をロードすることが唯一の解決策です

1
user9283245

Application/x-www-form-urlencodedおよびmultipart/from-dataを解析するために、falconフレームワークのrequest.pyに変更を追加しました。プルリクエストを発行しました- https://github.com/falconry/falcon/pull/1236 ですが、まだマスターにマージされていません。これを確認してください- https://github.com/branelmoro/falcon

POST、PUT、およびDELETE application/x-www-form-urlencodedおよびmultipart/form-dataを解析する新しいコードを追加しました。テキストフィールドはreq.form_data辞書で使用でき、アップロードファイルバッファストリームはreq.files辞書で使用できます。

これがPOSTとGETパラメーターに別々にアクセスし、同様にファイルをアップロードできるようになることを願っています。変更についての良い点は、アップロードされたファイル全体をメモリにロードしないことです。

以下は、POST、PUT、およびDELETEの使用方法を示すサンプルコードですapplication/x-www-form-urlencodedおよびmultipart/form-data:

import falcon

class Resource(object):

    def on_post(self, req, resp):

        # req.form_data will return dictionary of text field names and their values
        print(req.form_data)

        # req.form_data will return dictionary of file field names and
        # their buffer class FileStream objects as values
        print(req.files)

        # support we are uploading a image.jpg in `pancard` file field then
        # req.files["pancard"] will be FileStream buffer object

        # We can use set_max_upload_size method to set maximum allowed
        # file size let say 1Mb = 1*1024*1024 bytes for this file

        req.files["pancard"].set_max_upload_size(1*1024*1024)

        # We can use uploadto method to upload file on required path (Note: absolute filepath is required)
        # This method returns boolean - `True` on successful upload
        # and if upload is unsuccessful then it returns `False` and sets error on failure.
        path = "/tmp/" + req.files["pancard"].name

        response = req.files["pancard"].uploadto("/tmp/" + path)

        print(response)

        # Once file is uploaded sucessfully, we can check it's size
        print(req.files["pancard"].size)

        # If file is not uploaded sucessfully, we can check it's error
        print(req.files["pancard"].error)

        resp.body = "Done file upload"

        resp.status = falcon.HTTP_200

# falcon.API instances are callable WSGI apps
app = falcon.API()

things = Resource()

# things will handle post requests to the '/post_path' URL path
app.add_route('/post_path', things)

疑問がある場合はお知らせください。

1
Branel Moro

APIの設計中に使用したものを次に示します。

import falcon
import json


class VerifierResource():
    def on_post(self, req, resp):
        credentials = json.loads(req.stream.read())

        if credentials['username'] == USER \
          and credentials['passwd'] == PASSWORD:
            resp.body = json.dumps({"status": "verified"})
        else:
            resp.body = json.dumps({"status": "invalid"})

api = falcon.API()
api.add_route('/verify', VerifierResource())

これは、対応する応答本文を持つシリアル化されたJSONを返します。

0
roshnet