Невозможно сделать http-запрос на сервер django с помощью twisted.web.AGENT

Я написал базовую фабрику серверов tcp, серверный клиент и службу, используя Twisted. TCP-сервер действует как промежуточное ПО между сервером django и другой программой (назовем ее клиентской программой).

Чего я хочу добиться -

1. клиент запрашивает tcp-сервер промежуточного ПО;

2. отправляет строку в качестве тела запроса;

3. TCP-сервер промежуточного ПО десериализует информацию из запроса.

4.промежуточное ПО передает сериализованную информацию на сервер django.

5. Затем сервер django отвечает серверу промежуточного ПО, который передает ответ клиенту после сериализации ответа.

Я могу дойти до шага 3, но не могу сделать какой-либо http-запрос на сервер django.

Ниже приведен мой файл middleware.py.

from twisted.internet.protocol import ServerFactory
from twisted.internet.protocol import Protocol

from test_service import MyService


class TCPServerProtocol(Protocol):
    data = ''

    def connectionMade(self):
        self.deferred = self.factory.service.deferred
        self.deferred.addCallback(self.factory.service.s)
        self.deferred.addCallback(self.transport.write)
        self.deferred.addBoth(lambda r: self.transport.loseConnection)

    def dataReceived(self, data):
        self.data += data

    def connectionLost(self, reason):
        self.forward(self.data)

    def forward(self, data):
        if self.deferred is not None:
            d, self.deferred = self.deferred, None
            d.callback(data)

class TCPServerFactory(ServerFactory):

    protocol = TCPServerProtocol

    def __init__(self, service):
        self.service = service

def runserver(ip, port):
    iface =  {'home': '192.168.0.104', 'work': '127.0.0.1'}
    service = MyService()
    factory = TCPServerFactory(service)
    from twisted.internet import reactor
    reactor.listenTCP(port=port, factory=factory, interface=iface[ip])
    reactor.run()

if __name__ == '__main__':
    import sys
    ip = sys.argv[1]
    port = int(sys.argv[2])
    runserver(ip, port)

Ниже приведен файл test_service.py.

from twisted.internet.defer import Deferred

from test_http_client import HTTPClientFactory

class MyService(object):
    def __init__(self):
        self.deferred = Deferred()

    def s(self, data):
        kwargs = {}
        kwargs['url'] = b'http://127.0.0.1:8000/some/end/point'
        kwargs['url'] = kwargs['url'].encode('latin-1')
        kwargs['method'] = 'POST'
        kwargs['data'] = data

        client = HTTPClientFactory(**kwargs)
        d = client.deferred
        return d

Ниже приведен файл test_http_client.py.

from StringIO import StringIO
import json

from twisted.internet.protocol import Protocol
from twisted.internet.defer import Deferred
from twisted.web.client import Agent, FileBodyProducer
from twisted.web.http_headers import Headers


class HTTPClientProtocol(Protocol):
    def __init__(self, finished):
        self.finished = finished
        self.data = ''

    def dataReceived(self, data):
        print '----------Data Received by HTTPClientProtocol----------'
        print data
        self.data += data

    def connectionLost(self, reason):
        print '----------HTTP Client connection Lost----------'
        print reason.getErrorMessage()
        if self.finished is not None:
            print 'finished is not None'
            f, self.finished = self.finished, None
            f.callback(self.data)

class HTTPClientFactory(object):

    """
    Class handling communication with HTTP server.
    """

    def __init__(self, **kwargs):
        data = kwargs['data'] 
        try:
            body = FileBodyProducer(StringIO(json.dumps(data)))
            print '----------Request body object created----------'
        except Exception as e:
            print '----------Request body object creation FAILURE----------'
            print e
            return e  
        url = kwargs.get('url', None)
        method = kwargs.get('method', None)

        from twisted.internet import reactor
        agent = Agent(reactor)
        if not data:
            body = None

        self.deferred = agent.request(method,
                                    url,
                                    Headers({'Content-Type': ['application/json']}),
                                    bodyProducer=body)

        self.deferred.addCallback(self.get_response)

    def get_response(self, response):
        print 'Response received'
        finished = Deferred()
        response.deliverBody(HTTPClientProtocol(finished))
        return finished

РЕДАКТИРОВАНИЕ Удален код, который зависел от другого кода, не имеющего отношения к проблеме.


person HumptyDumptyEIZ    schedule 02.11.2015    source источник
comment
Можете ли вы попытаться сократить это до sscce.org? Здесь не хватает большого количества кода, поэтому я не могу попытаться запустить ваш пример. Как бы то ни было, присутствие Django на серверной части здесь не имеет значения: это просто Twisted, делающий HTTP-запрос. Как вы определили, он работает изолированно, поэтому какое-то сложное взаимодействие с остальной частью вашей системы вызывает проблемы, и, не видя остальную часть вашей системы в целом, я не могу сказать, что это такое. (Попытки отлаживать всю систему никому не нужны, поэтому чем больше вы сможете сузить область, тем лучше.)   -  person Glyph    schedule 03.11.2015


Ответы (1)


Нашел ошибку. Ниже приведен исправленный код.

class TCPServerProtocol(Protocol):

    # data = ''

    def connectionMade(self):
        self.deferred = self.factory.service.deferred
        self.deferred.addCallback(self.factory.service.s)
        self.deferred.addCallback(self.transport.write)
        self.deferred.addBoth(lambda r: self.transport.loseConnection)

    def dataReceived(self, data):
        self.data = data           # instead of self.data += data
        self.forward(self.data)    # this is the right place to call this method which in turn fires the callback through which the request is made to the server.

    def connectionLost(self, reason): pass
        # this will not be called until the connection from client is ended. 
        # self.forward(self.data)

    def forward(self, data):
        if self.deferred is not None:
            d, self.deferred = self.deferred, None
            d.callback(data)
person HumptyDumptyEIZ    schedule 13.11.2015
comment
Этот код является синтаксической ошибкой, поэтому я не уверен, что он полностью исправлен :). Я думаю, вы можете полностью исключить self.data? - person Glyph; 04.12.2015