プロジェクトで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データを取得するには?
助けてくれてありがとう
問題を少し掘り下げると、次のようになりました 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リクエストデータを受信します。パフォーマンス上の理由により、データの上で適切な解析を実行してより使いやすいデータ構造に変換することはできません。
探しているフィールドの名前はやや紛らわしいですが、 req.media です:
要求ストリームの逆シリアル化された形式を返します。呼び出されると、Content-Typeヘッダーと
falcon.RequestOptions
で構成されたメディアタイプハンドラーを使用して、要求ストリームの逆シリアル化を試みます。
リクエストがJSONの場合、req.media
にはpython dict。
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())
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)
これまで...私にとっては、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に文字列をロードすることが唯一の解決策です
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)
疑問がある場合はお知らせください。
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を返します。