在代理HTTP请求时阻止Django阻塞

时间:2014-04-04 13:26:48

标签: django http nginx proxy uwsgi

我正在开发一个Django站点,该站点允许通过云服务连接到受限网络中的设备。设备通过VPN或SSH隧道连接到云服务器,客户端通过HTTP连接到虚拟主机。 Django部分是管理复杂的组织 - 角色 - 访问 - 用户关系所必需的。

目前我正在自定义Django中间件模块中进行访问控制,该模块解析HTTP_HOST,进行身份验证,获取页面并将其转发给原始请求者。问题是,当请求正在进行时,Django不会处理任何其他请求。 Celery没有解决问题,因为这不是一个真正的后台任务。客户端通过单个地址和端口提供服务,使防火墙规则不适合此任务。

相关代码如下:

class NodeProxyMiddleware:

    def process_request(self, request, *args, **kwargs):
        if not 'HTTP_HOST' in request.META:
            return None
        hardware_id = match_hwid.match(request.META["HTTP_HOST"])
        if not hardware_id:
            return None
        kwargs["hardware_id"] = hardware_id.group("hwid")
        if not authenticate(request, *args, **kwargs):
            return HttpResponseForbidden("No access")
        return proxy_request(request, *args, **kwargs)

@csrf_exempt
def proxy_request(request, *args, **kwargs):

    # Get the port of target Node
    hardware_id = kwargs.get("hardware_id", "")
    try:
        port = Node.objects.filter(hardware_id=hardware_id)[0].port
    except IndexError:  # Node with given hwid was not found
        raise Http404

    # We have to convert request.META back to original form manually
    headers = convert_headers(request)  # HTTP_FOO_BAR to Foo-Bar
    headers["connection"] = "close"
    connection = httplib2.Http(timeout=5)
    url = "http://127.0.0.1:%d%s" % (port, request.META['PATH_INFO'])
    method = request.method

    # GET -- url ?d=a&t=a has to be urlencoded
    if method == "GET":
        data = None
        if request.GET:
            url += "?" + request.GET.urlencode()

    # POST -- body has to be urlencoded
    elif method == "POST":
        data = request.POST.urlencode()
        headers["content-type"] = "application/x-www-form-urlencoded"

    try:
        response, content = connection.request(
            url, method, data, headers=headers)
    except Exception as e:
        print e
        return HttpResponse(content=e, status=503)

    django_response = HttpResponse(
        content=content,
        status=int(response["status"]),
        mimetype=response["content-type"],
    )

    # Strip hop-by-hop headers -- See RFC2616 semantically transparent
    # proxying. Also, WSGI forbids passing such headers back to it.
    hop_by_hop_headers = [
        "connection",
        "keep-alive",
        "proxy-authenticate",
        "proxy-authorization",
        "te",
        "trailers",
        "transfer-encoding",
        "upgrade",
    ]
    for key, value in response.iteritems():
        if key.lower() in hop_by_hop_headers:
            continue
        django_response[key] = value

    return django_response

通过调整上面的代码或其他设置,可以在Django中完成这种代理吗?我正在运行的软件堆栈是Nginx + uWSGI + Django 1.6。 uWSGI配置为:

[uwsgi]
chdir           = /home/foo/production/
file            = /home/foo/production/wsgi.py
home            = /home/foo/virtualenv
master          = true
processes       = 8
socket          = /var/nginx/foo.socket
chmod-socket    = 666
vacuum          = true
daemonize       = /home/foo/production/uwsgi.log

0 个答案:

没有答案