Python 从 Flask 返回一个 requests.Response 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19568950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Return a requests.Response object from Flask
提问by Fred Foo
I'm trying to build a simple proxy using Flask and requests. The code is as follows:
我正在尝试使用 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
This works, except that it loses the status code from Elasticsearch. I tried returning resp
(a requests.models.Response
) directly, but this fails with
这有效,只是它丢失了来自 Elasticsearch 的状态代码。我尝试直接返回resp
(a requests.models.Response
),但这失败了
TypeError: 'Response' object is not callable
Is there another, simple, way to return a requests.models.Response
from Flask?
还有另一种简单的方法可以requests.models.Response
从 Flask返回 a吗?
采纳答案by Fred Foo
Ok, found it:
好的,找到了:
If a tuple is returned the items in the tuple can provide extra information. Such tuples have to be in the form (response, status, headers) where at least one item has to be in the tuple. The status value will override the status code and headers can be a list or dictionary of additional header values.
如果返回元组,元组中的项目可以提供额外信息。此类元组必须采用(响应、状态、标题)形式,其中元组中必须至少包含一项。状态值将覆盖状态代码,标题可以是附加标题值的列表或字典。
(Flask docs.)
(烧瓶文档。)
So
所以
return (resp.text, resp.status_code, resp.headers.items())
seems to do the trick.
似乎可以解决问题。
回答by Emilia Apostolova
I ran into the same scenario, except that in my case my requests.models.Response contained an attachment. This is how I got it to work:
我遇到了同样的情况,除了在我的情况下我的 requests.models.Response 包含一个附件。这就是我让它工作的方式:
return send_file(BytesIO(result.content), mimetype=result.headers['Content-Type'], as_attachment=True)
返回 send_file(BytesIO(result.content), mimetype=result.headers['Content-Type'], as_attachment=True)
回答by Smi
Using text
or content
property of the Response
object will not work if the server returns encoded data (such as content-encoding: gzip
) and you return the headers unchanged. This happens because text
and content
have been decoded, so there will be a mismatch between the header-reported encoding and the actual encoding.
使用text
或content
在财产Response
对象将不会工作,如果服务器返回编码数据(如content-encoding: gzip
)并返回头不变。发生这种情况是因为text
并且content
已经被解码,所以报头报告的编码和实际编码之间会存在不匹配。
According to the documentation:
根据文档:
In the rare case that you'd like to get the raw socket response from the server, you can access
r.raw
. If you want to do this, make sure you setstream=True
in your initial request.
在极少数情况下,您希望从服务器获取原始套接字响应,您可以访问
r.raw
. 如果您想这样做,请确保您stream=True
在初始请求中进行了设置。
and
和
Response.raw
is a raw stream of bytes – it does not transform the response content.
Response.raw
是一个原始字节流——它不会转换响应内容。
So, the following works for gzipped data too:
因此,以下内容也适用于 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()
If you use a shortcut method such as get
, it's just:
如果您使用诸如 的快捷方法get
,则它只是:
resp = requests.get(url, stream=True)
return resp.raw.read(), resp.status_code, resp.headers.items()
回答by Zhanwen Chen
My use case is to call another API in my own Flask API. I'm just propagating unsuccessful requests.get
calls through my Flask response. Here's my successful approach:
我的用例是在我自己的 Flask API 中调用另一个 API。我只是requests.get
通过 Flask 响应传播不成功的调用。这是我成功的方法:
headers = {
'Authorization': 'Bearer Muh Token'
}
try:
response = requests.get(
'{domain}/users/{id}'\
.format(domain=USERS_API_URL, id=hit['id']),
headers=headers)
response.raise_for_status()
except HTTPError as err:
logging.error(err)
flask.abort(flask.Response(response=response.content, status=response.status_code, headers=response.headers.items()))