web-dev-qa-db-ja.com

Flaskからrequests.Responseオブジェクトを返します

Flaskとリクエストを使用して単純なプロキシを構築しようとしています。コードは次のとおりです。

@app.route('/es/<string:index>/<string:type>/<string:id>',
           methods=['GET', 'POST', 'PUT']):
def es(index, type, id):
    elasticsearch = find_out_where_elasticsearch_lives()
    # also handle some authentication
    url = '%s%s%s%s' % (elasticsearch, index, type, id)

    esreq = requests.Request(method=request.method, url=url,
                             headers=request.headers, data=request.data)
    resp = requests.Session().send(esreq.prepare())
    return resp.text

これは機能しますが、Elasticsearchからのステータスコードが失われます。 resprequests.models.Response)を直接返そうとしましたが、これは失敗します

TypeError: 'Response' object is not callable

Flaskからrequests.models.Responseを返す別の簡単な方法はありますか?

34
Fred Foo

わかりました、見つけました:

タプルが返される場合、タプル内のアイテムは追加情報を提供できます。このようなタプルは、少なくとも1つの項目がタプルにある必要がある形式(応答、ステータス、ヘッダー)である必要があります。ステータス値はステータスコードをオーバーライドし、ヘッダーは追加のヘッダー値のリストまたは辞書にすることができます。

Flask docs 。)

そう

return (resp.text, resp.status_code, resp.headers.items())

トリックをするようです。

59
Fred Foo

サーバーがエンコードを返した場合、 text オブジェクトのcontentまたはResponseプロパティを使用しても機能しません。データ(content-encoding: gzipなど)で、ヘッダーを変更せずに返します。これは、textcontentがデコードされているために発生します。そのため、ヘッダーで報告されたエンコードと実際のエンコードが一致しなくなります。

ドキュメント によると:

サーバーから生のソケットレスポンスを取得したいというまれなケースでは、r.rawにアクセスできます。これを行う場合は、最初のリクエストでstream=Trueを必ず設定してください。

そして

Response.rawはバイトの生ストリームであり、応答コンテンツを変換しません。

そのため、以下はgzip圧縮されたデータでも機能します。

esreq = requests.Request(method=request.method, url=url,
                         headers=request.headers, data=request.data)
resp = requests.Session().send(esreq.prepare(), stream=True)
return resp.raw.read(), resp.status_code, resp.headers.items()

getなどのショートカットメソッドを使用する場合、次のようになります。

resp = requests.get(url, stream=True)
return resp.raw.read(), resp.status_code, resp.headers.items()
6
Smi

私の場合、requests.models.Responseに添付ファイルが含まれていたことを除いて、同じシナリオに遭遇しました。これは私がそれを機能させる方法です:

return send_file(BytesIO(result.content)、mimetype = result.headers ['Content-Type']、as_attachment = True)

0