2015-04-02 80 views
1

我有以下代码片段,从原始的docs稍作修改。当url设置为http://google.com时,代码正常工作。但是当它改为http://www.google.com时它崩溃了。崩溃时的错误是Failure: twisted.web.client.PartialDownloadError: 200 OK。回溯在代码片段之下。Twisted giving twisted.web.client.PartialDownloadError:200 OK

最初我以为可能代码崩溃,因为没有正确处理SSL。但是,看看这些标题看起来不是问题。这是我第一次与Twisted一起工作;我不知道还有什么可能导致这个问题。

代码

from sys import argv 
from pprint import pformat 
from twisted.internet.task import react 
from twisted.web.client import Agent, BrowserLikeRedirectAgent, readBody 
from twisted.web.http_headers import Headers 
from twisted.internet import reactor 
from twisted.internet.ssl import ClientContextFactory 

responses = [] 

class WebClientContextFactory(ClientContextFactory): 
    def getContext(self, hostname, port): 
     return ClientContextFactory.getContext(self) 

def cbBody(r): 
    print 'Response body:' 
    print r 
    responses.append(r) 

def cbRequest(response): 
    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 main(reactor): 
    contextFactory = WebClientContextFactory() 
    agent = BrowserLikeRedirectAgent(Agent(reactor, contextFactory)) 
    url=b"http://google.com/" 
    agent = Agent(reactor, contextFactory) 
    d = agent.request(
     'GET', url, 
     Headers({'User-Agent': ['Twisted Web Client Example']}), 
     None) 
    d.addCallback(cbRequest) 
    return d 

react(main) 

回溯

In [1]: %tb 
--------------------------------------------------------------------------- 
SystemExit        Traceback (most recent call last) 
/usr/local/lib/python2.7/site-packages/IPython/utils/py3compat.pyc in execfile(fname, glob, loc, compiler) 
    218    else: 
    219     scripttext = builtin_mod.open(fname).read().rstrip() + '\n' 
--> 220     exec(compiler(scripttext, filename, 'exec'), glob, loc) 
    221 
    222 

/project/demo.py in <module>() 
    42  return d 
    43 
---> 44 react(main) 

/usr/local/lib/python2.7/site-packages/twisted/internet/task.pyc in react(main, argv, _reactor) 
    902  finished.addBoth(cbFinish) 
    903  _reactor.run() 
--> 904  sys.exit(codes[0]) 
    905 
    906 

SystemExit: 1 

回答

2

它不应该是太令人吃惊,对于不同的URL请求,产生不同反应。这些URL标识不同的资源。在请求不同的资源时,您应该期望获得不同的响应。

当您请求http://www.google.com/时,得到PartialDownloadError的原因是Google发送的响应中既没有Content-Length也没有Transfer-Encoding: chunked。这意味着客户端知道何时收到响应的唯一方法是TCP连接关闭。不幸的是,由于其他原因,TCP连接可能会关闭 - 所以答复是否被完全接收是不明确的。

Google似乎在回应Agent发出请求的具体细节时以这种方式构建响应。谷歌回应Transfer-Encoding: chunked对其他代理的请求。

解决这个问题的一个方法是决定你不关心在你不知情的情况下截断了响应。在这种情况下,请向处理PartialDownloadErrorreadBodyDeferred添加errback。异常具有response属性,可为您提供在TCP连接关闭前读取的数据。抓住这些数据并返回它,现在你已经将可能失败的案例转换成了who-cares-pretend-it-succeeded案例。

另一个选择是尝试摆弄请求的细节,直到你说服Google给你一个Transfer-Encoding: chunked(或至少一个Content-Length)。当然,只要你遇到另一台服务器,这个解决方案就会中断,而这个服务器不会给你一个或另一个服务器。

+0

最终,它看起来像用户代理标题是问题。模仿标准的Mozilla请求修复了这个问题。谢谢! – Chris 2015-04-03 14:12:00

+0

我不清楚你的评论“异常有一个响应属性给你的数据,直到TCP连接关闭读取。”我相信这将通过'failure.value'访问,但在我的情况下,程序只返回“200 OK”。我访问一个不正确的属性,或者这实际上是唯一收到的TCP数据? – Chris 2015-04-03 15:03:53