[Django]-Django as reverse proxy

3👍

I went ahead and built a simple prototype. It was relatively simple, I just had to set up a view that maps all URLs I want to redirect. The view function looks something like this:

def redirect(request):
    url = "http://%s%s" % (server, request.path)
    # add get parameters
    if request.GET:
        url += '?' + urlencode(request.GET)

    # add headers of the incoming request
    # see https://docs.djangoproject.com/en/1.7/ref/request-response/#django.http.HttpRequest.META for details about the request.META dict
    def convert(s):
        s = s.replace('HTTP_','',1)
        s = s.replace('_','-')
        return s

    request_headers = dict((convert(k),v) for k,v in request.META.iteritems() if k.startswith('HTTP_'))
    # add content-type and and content-length
    request_headers['CONTENT-TYPE'] = request.META.get('CONTENT_TYPE', '')
    request_headers['CONTENT-LENGTH'] = request.META.get('CONTENT_LENGTH', '')

    # get original request payload
    if request.method == "GET":
        data = None
    else:
        data = request.raw_post_data

    downstream_request = urllib2.Request(url, data, headers=request_headers)
    page = urllib2.urlopen(downstream_request)
    response = django.http.HttpResponse(page)
    return response

So it is actually quite simple and the performance is good enough, in particular if the redirect goes to the loopback interface on the same host.

3👍

Usually in production, you are hosting Django behind a web container like Apache httpd or nginx. These have modules designed for proxying requests (e.g. proxy_pass for a location in nginx). They give you some extras out of the box like caching if you need it. Compared with proxying through a Django application’s request pipeline this may save you development time while delivering better performance. However, you sacrifice the power to completely manipulate the request or proxied response when you use a solution like this.

For local testing with ./manage.py runserver, I add a url pattern via urls.py in an if settings.DEBUG: ... section. Here’s the view function code I use, which supports GET, PUT, and POST using the requests Python library: https://gist.github.com/JustinTArthur/5710254

Leave a comment