2015-04-02 81 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