Proxy vers un autre service web avec Flask
Je veux proxy les demandes faites à mon application Flask à un autre service web s'exécutant localement sur la machine. Je préfère utiliser Flask pour cela que notre instance NGINX de niveau supérieur afin que nous puissions réutiliser notre système d'authentification existant intégré dans notre application. Plus nous pouvons garder ce "single sign on" mieux c'est.
Existe-t-il un module existant ou un autre code pour le faire? Essayer de relier L'application Flask à quelque chose comme httplib ou urllib s'avère être une douleur.
3 réponses
J'ai une implémentation d'un proxy utilisant httplib dans une application basée sur Werkzeug (comme dans votre cas, j'avais besoin d'utiliser l'authentification et l'autorisation de l'application web).
Bien que les documents Flask n'indiquent pas comment accéder aux en-têtes HTTP, vous pouvez utiliser request.headers
(voir la documentation Werkzeug ). Si vous n'avez pas besoin de modifier la réponse et que les en-têtes utilisés par l'application proxyée sont prévisibles, le proxy est staightforward.
Notez que si vous n'avez pas besoin de modifier la réponse, vous devrait utiliser le werkzeug.wsgi.wrap_file
pour envelopper le flux de réponse de httplib. Cela permet de passer du descripteur de fichier ouvert au niveau du système d'exploitation au serveur HTTP pour des performances optimales.
J'ai passé beaucoup de temps à travailler sur la même chose et j'ai finalement trouvé une solution en utilisant la bibliothèque requests qui semble bien fonctionner. Il gère même la définition de plusieurs cookies dans une réponse, ce qui a pris un peu d'enquête pour comprendre. Voici la fonction flask view:
from flask import request, Response
import requests
def _proxy(*args, **kwargs):
resp = requests.request(
method=request.method,
url=request.url.replace('old-domain.com', 'new-domain.com'),
headers={key: value for (key, value) in request.headers if key != 'Host'},
data=request.get_data(),
cookies=request.cookies,
allow_redirects=False)
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
headers = [(name, value) for (name, value) in resp.raw.headers.items()
if name.lower() not in excluded_headers]
response = Response(resp.content, resp.status_code, headers)
return response
Mon plan initial était que l'URL publique soit quelque chose comme http://www.example.com/admin/myapp
proxy à http://myapp.internal.example.com/
. En bas de ce chemin mène la folie.
La plupart des webapps, en particulier les webapps auto-hébergés, supposent qu'ils vont s'exécuter à la racine D'un serveur HTTP et faire des choses comme référencer d'autres fichiers par chemin absolu. Pour contourner ce problème, vous devez réécrire les URL partout: les en-têtes D'emplacement et les fichiers HTML, JavaScript et CSS.
J'ai fait écrire un plan proxy Flask qui fait cela, et alors que cela fonctionnait assez bien pour la webapp que je voulais vraiment proxy, ce n'était pas durable. C'était un gros gâchis d'expressions régulières.
À la fin, j'ai mis en place un nouvel hôte virtuel dans nginx et utilisé son propre proxy. Puisque les deux étaient à la racine de l'hôte, la réécriture D'URL était surtout inutile. (Et quel peu était nécessaire, le module proxy de nginx géré.) La webapp en cours de proxy fait sa propre authentification, ce qui est assez bon pour l'instant.