Django as reverse proxy

2019-04-11 08:01发布

My client-server application is mainly based on special purpose http server that communicates with client in an Ajax like fashion, ie. the client GUI is refreshed upon asynchronous http request/response cycles.

Evolvability of the special purpose http server is limited and as the application grows, more and more standard features are needed which are provided by Django for instance.

Hence, I would like to add a Django application as a facade/reverse-proxy in order to hide the non-standard special purpose server and be able to gain from Django. I would like to have the Django app as a gateway and not use http-redirect for security reasons and to hide complexity.

However, my concern is that tunneling the traffic through Django on the serer might spoil performance. Is this a valid concern?

Would there be an alternative solution to the problem?

2条回答
你好瞎i
2楼-- · 2019-04-11 08:11

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

查看更多
姐就是有狂的资本
3楼-- · 2019-04-11 08:18

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.

查看更多
登录 后发表回答