J'essaie de construire un simple proxy en utilisant Flask et requêtes. Le code est le suivant:
@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
Cela fonctionne, sauf qu'il perd le code d'état d'Elasticsearch. J'ai essayé de renvoyer resp
(un requests.models.Response
) directement, mais cela échoue avec
TypeError: 'Response' object is not callable
Existe-t-il un autre moyen simple de renvoyer un requests.models.Response
de Flask?
Ok, je l'ai trouvé:
Si un tuple est retourné, les éléments du tuple peuvent fournir des informations supplémentaires. Ces tuples doivent être sous la forme (réponse, statut, en-têtes) où au moins un élément doit être dans le tuple. La valeur d'état remplacera le code d'état et les en-têtes peuvent être une liste ou un dictionnaire de valeurs d'en-tête supplémentaires.
( Flask docs .)
Alors
return (resp.text, resp.status_code, resp.headers.items())
semble faire l'affaire.
L'utilisation de la propriété text
ou content
de l'objet Response
ne fonctionnera pas si le serveur renvoie des données codées (telles que content-encoding: gzip
) et vous retournez les en-têtes inchangés. Cela se produit car text
et content
ont été décodés, il y aura donc une incompatibilité entre l'encodage signalé par l'en-tête et l'encodage réel.
Selon la documentation :
Dans les rares cas où vous souhaitez obtenir la réponse de socket brute du serveur, vous pouvez accéder à
r.raw
. Pour ce faire, assurez-vous de définirstream=True
dans votre demande initiale.
et
Response.raw
est un flux d'octets brut - il ne transforme pas le contenu de la réponse.
Donc, ce qui suit fonctionne aussi pour les données gzippées:
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()
Si vous utilisez une méthode de raccourci telle que get
, c'est juste:
resp = requests.get(url, stream=True)
return resp.raw.read(), resp.status_code, resp.headers.items()
J'ai rencontré le même scénario, sauf que dans mon cas, mon request.models.Response contenait une pièce jointe. Voici comment je l'ai fait fonctionner:
return send_file (BytesIO (result.content), mimetype = result.headers ['Content-Type'], as_attachment = True)