Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proxying to another web service with Flask

I want to proxy requests made to my Flask app to another web service running locally on the machine. I'd rather use Flask for this than our higher-level nginx instance so that we can reuse our existing authentication system built into our app. The more we can keep this "single sign on" the better.

Is there an existing module or other code to do this? Trying to bridge the Flask app through to something like httplib or urllib is proving to be a pain.

like image 977
Joe Shaw Avatar asked Jul 11 '11 20:07

Joe Shaw


People also ask

How do I setup a proxy server in Flask?

From here, we simply import Flask, and requests. Repl.it will install these modules when you run it. We're using requests to fetch for the site we're proxying. Then, we create an app instance, which we will use to run the server.

Does Flask create a Web server?

Warning Flask uses a simple web server to serve our application in a development environment, which also means that the Flask debugger is running to make catching errors easier. This development server should not be used in a production deployment.

How does Python connect to proxy server?

To use a proxy in Python, first import the requests package. Next create a proxies dictionary that defines the HTTP and HTTPS connections. This variable should be a dictionary that maps a protocol to the proxy URL. Additionally, make a url variable set to the webpage you're scraping from.

Does Flask need a Web server?

Although Flask has a built-in web server, as we all know, it's not suitable for production and needs to be put behind a real web server able to communicate with Flask through a WSGI protocol. A common choice for that is Gunicorn—a Python WSGI HTTP server.


2 Answers

I spent a good deal of time working on this same thing and eventually found a solution using the requests library that seems to work well. It even handles setting multiple cookies in one response, which took a bit of investigation to figure out. Here's the flask view function:

from flask import request, Response import requests  def _proxy(*args, **kwargs):     resp = requests.request(         method=request.method,         url=request.url.replace(request.host_url, '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 

Update April 2021: excluded_headers should probably include all "hop-by-hop headers" defined by RFC 2616 section 13.5.1.

like image 189
Evan Avatar answered Sep 23 '22 08:09

Evan


I have an implementation of a proxy using httplib in a Werkzeug-based app (as in your case, I needed to use the webapp's authentication and authorization).

Although the Flask docs don't state how to access the HTTP headers, you can use request.headers (see Werkzeug documentation). If you don't need to modify the response, and the headers used by the proxied app are predictable, proxying is staightforward.

Note that if you don't need to modify the response, you should use the werkzeug.wsgi.wrap_file to wrap httplib's response stream. That allows passing of the open OS-level file descriptor to the HTTP server for optimal performance.

like image 22
jd. Avatar answered Sep 21 '22 08:09

jd.