2011-07-11 5 views
19

Deseo enviar las solicitudes de proxy a mi aplicación Flask a otro servicio web que se ejecute localmente en la máquina. Prefiero usar Flask para esto que nuestra instancia de nginx de nivel superior para que podamos reutilizar nuestro sistema de autenticación existente integrado en nuestra aplicación. Mientras más podamos mantener este "inicio de sesión único", mejor.Proxingir a otro servicio web con el Flask

¿Existe un módulo u otro código para hacer esto? Tratar de conectar la aplicación Flask con algo como httplib o urllib está demostrando ser un dolor.

+0

También esta pregunta es relevante cuando se realizan servicios AJAX para navegadores antiguos como IE7 que no admiten seguridad entre dominios. –

+0

¿Qué problema específico tiene con httplib? –

+0

@jd: Dado que el matraz está en el lado de la aplicación de WSGI, no estoy seguro de obtener todos los datos para reenviar de manera efectiva. Por ejemplo, el objeto de solicitud de Flask no parece incluir la solicitud en bruto (o incluso los encabezados de solicitud) que quisiera pasar a httplib. No es que sea imposible, es solo un dolor y esperaba un módulo existente que ya lo hizo. –

Respuesta

8

Tengo una implementación de un proxy usando httplib en una aplicación basada en Werkzeug (como en su caso, necesitaba usar la autenticación y autorización de la aplicación web).

Aunque los documentos del Flask no indican cómo acceder a los encabezados HTTP, puede usar request.headers (consulte Werkzeug documentation). Si no necesita modificar la respuesta, y los encabezados utilizados por la aplicación de proxy son predecibles, el proxy es continuo.

Tenga en cuenta que si no necesita modificar la respuesta, debe usar werkzeug.wsgi.wrap_file para ajustar la secuencia de respuesta de httplib. Eso permite pasar el descriptor de archivo de nivel de SO abierto al servidor HTTP para un rendimiento óptimo.

+0

Gracias, esta semana he pirateado algo. Sin embargo, tiene todo tipo de problemas con las cookies, ya que httplib no los maneja particularmente bien. Lamentablemente, creo que tendré que modificar la respuesta para hacer algunas reescrituras URL simples (es decir, a

+0

En mi caso solo había una cookie para capturar, por lo que una expresión regular hizo el trabajo de analizarla, es mucho más fácil configurar las librerías de cookies de Python. –

7

Mi plan original era que la URL pública fuera algo así como http://www.example.com/admin/myapp proxying a http://myapp.internal.example.com/. Por ese camino lleva la locura.

La mayoría de los webapps, especialmente los autohospedados, asumen que se ejecutarán en la raíz de un servidor HTTP y hacen cosas como referenciar otros archivos por ruta absoluta. Para evitar esto, debe volver a escribir las URL en cualquier lugar: encabezados de ubicación y archivos HTML, JavaScript y CSS.

Hice write a Flask proxy blueprint que hizo esto, y si bien funcionó lo suficientemente bien para la única aplicación web que realmente quería proxy, no era sostenible. Fue un gran lío de expresiones regulares.

Al final, configuré un nuevo host virtual en nginx y usé su propio proxying. Dado que ambos estaban en la raíz del host, la reescritura de URL fue en su mayoría innecesaria. (Y lo poco que fue necesario, se manejó el módulo de proxy de nginx). La aplicación de Internet a la que se hace el proxy realiza su propia autenticación, que es lo suficientemente buena por ahora.

+0

volvería a leer 7/10 –

19

Pasé mucho tiempo trabajando en esto mismo y, finalmente, encontré una solución utilizando la solicitudes de biblioteca que parece funcionar bien. Incluso maneja la configuración de múltiples cookies en una respuesta, lo que llevó un poco de investigación para resolver. Aquí está la función de vista del matraz:

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 
+1

Editado solo ahora para eliminar 'Host' de los encabezados de solicitud y eliminar algunos elementos de los encabezados de respuesta. – Evan

+1

'headers' parece estar sin usar? – luckydonald

+1

@luckydonald Creo que está arreglado ahora. Gracias por señalar eso. – Evan

Cuestiones relacionadas