2

我有一个使用 Twisted 编写的小型 Web 服务器。我想做的一件事是让它从另一个 Web 服务器返回一个结果作为加载页面的响应。也就是说,服务器 A(通过http://A.com/resource)对 render_GET() 的响应应该是服务器 B 上不同 URL 的内容(通过http://B.com/resource2)。服务器 B 返回的内容是动态的,所以我不能只缓存它。

现在,服务器 A 可以很好地渲染页面,它只是无法渲染这个远程资源。我已经尝试过使用 Agent(),但我似乎无法从 B 获得响应,更不用说将其转发给 A。我知道我必须在某个地方从 render_GET 以及稍后接收该write()请求finish()。这是在cbBody回调中完成的,它被调用但无法到达原始请求来填充它。

这是服务器 A 的资源处理程序的一段代码:

def render_GET(self,request):
    # try with canned content just to test the whole thing
    bmpServer = BMPServer(ServerBURL,
                          "xyzzy",
                          "plugh")
    d= bmpServer.postNotification({"a":123},request)
    print "Deferred", d
    return NOT_DONE_YET

这是服务器 A 上的另一个代码:

theRequest = None

def cbRequest(response,args):
    print "response called"
    print response
    print args
    print 'Response version:', response.version
    print 'Response code:', response.code
    print 'Response phrase:', response.phrase
    print 'Response headers:'
    print pformat(list(response.headers.getAllRawHeaders()))  
    d = readBody(response)
    d.addCallback(cbBody)
    return d

def cbBody(body):
    print "Response body:"
    print body
    theRequest.write(body)
    theRequest.finish()
    theRequest = None

def cbError(failure):
    print type(failure.value), failure # catch error here
    print failure.value.reasons[0].printTraceback()

class BMPServer(object):
    def __init__(self,url,arg1,arg2):
        self.url = url
        self.arg1 = arg1
        self.arg2 = arg2

    def postNotification(self,message,request):
        theRequest = request
        bmpMessage = {'arg1':self.token,
                      'arg2':self.appID,
                      'message':message}
        print "Sending request to %s"%self.url

        print "Create agent"
        agent = Agent(reactor)
        print "create request deferred"
        print "url = %s" % self.url
        d = agent.request('POST', self.url,
                          Headers({'User-Agent': ['Twisted Web Client Example']}),
                          MessageProducer(bmpMessage))
        print "adding callback"
        d.addCallbacks(cbRequest,cbError)
        print "returning deferred"
        return d

当我将其作为独立代码运行时(react()例如在资源之外,使用),它可以正常工作。但是,当我尝试如上所示包含它时,它似乎永远不会收到数据。我已经运行了 WireShark,所以我可以看到响应正在从服务器 B 返回,但数据从未出现在cbRequest().

例如,这是我看到的输出:

Sending request to http://localhost:8888/postMGCMNotificationService
Create agent
create request deferred
url = http://serverB:8888/postService
Message producer: body = {"arg2": "plugh", "arg1": "xyzzy", "message": {"a": 1}}
adding callback
returning deferred
testAgent: returning deferred
<Deferred at 0x10b54d290>
Writing body now
response called
<twisted.web._newclient.Response object at 0x1080753d0>
Response version: ('HTTP', 1, 1)
Response code: 200
Response phrase: OK
Response headers:
Response body:
{"result": false}
^CUnhandled error in Deferred:
Unhandled Error
Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/Twisted-13.1.0_r39314-py2.7-macosx-10.8-intel.egg/twisted/web/_newclient.py", line 1151, in _bodyDataFinished_CONNECTED
    self._bodyProtocol.connectionLost(reason)
  File "/Library/Python/2.7/site-packages/Twisted-13.1.0_r39314-py2.7-macosx-10.8-intel.egg/twisted/web/client.py", line 1793, in connectionLost
    self.deferred.callback(b''.join(self.dataBuffer))
  File "/Library/Python/2.7/site-packages/Twisted-13.1.0_r39314-py2.7-macosx-10.8-intel.egg/twisted/internet/defer.py", line 382, in callback
    self._startRunCallbacks(result)
  File "/Library/Python/2.7/site-packages/Twisted-13.1.0_r39314-py2.7-macosx-10.8-intel.egg/twisted/internet/defer.py", line 490, in _startRunCallbacks
    self._runCallbacks()
--- <exception caught here> ---
  File "/Library/Python/2.7/site-packages/Twisted-13.1.0_r39314-py2.7-macosx-10.8-intel.egg/twisted/internet/defer.py", line 577, in _runCallbacks
    current.result = callback(current.result, *args, **kw)
  File "AServer.py", line 85, in cbBody
    print theRequest
exceptions.UnboundLocalError: local variable 'theRequest' referenced before assignment

再看看这个,似乎如果我能想出一种方法来让这个请求结束,cbBody()一切都会很好。

4

1 回答 1

4

您可以将额外的参数传递给 a 上的回调Deferred

d.addCallback(f, x)

当 d 触发时,结果是f(result of d, x). 您可以通过这种方式传递任意数量的位置或关键字参数。有关详细信息,请参阅API 文档。Deferred

于 2013-08-14T11:56:18.400 回答