web-dev-qa-db-fra.com

Renvoyer un objet request.Response de Flask

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?

34
Fred Foo

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.

59
Fred Foo

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éfinir stream=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()
6
Smi

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)

0
Emilia Apostolova