2013-05-06 27 views
1

環境:Python的2.7.4(部分在Windows上,部分在Linux上,見下文),泡沫(含有少量的修改SVN HEAD)嵌套文本編碼請求

我需要調用,需要一個Web服務一個參數,它是一個XML字符串(是的,我知道...),即請求與以下類型的WSDL聲明:

<s:complexType> 
    <s:sequence> 
    <s:element minOccurs="0" maxOccurs="1" name="actionString" type="s:string"/> 
    </s:sequence> 
</s:complexType> 

我使用cElementTree構建這種內在的XML文檔,然後我將它作爲泡沫產生的client.service.ProcessAction(request)方法的唯一參數傳遞給它。

有一段時間,這個效果不錯:

root = ET.Element(u'ActionCommand') 
value = ET.SubElement(root, u'value') 
value.text = saxutils.escape(complex_value) 
request = u'<?xml version="1.0" encoding="utf-8"?>\n' + ET.tostring(root, encoding='utf-8') 
client.service.ProcessAction(request) 

saxutils.escape,我在某些時候又增加了固定第一編碼的問題,幾乎沒有能夠明白到底爲什麼我需要它,有什麼區別它使。

現在(可能是由於英鎊符號第一次出現的),我突然得到了以下異常:

Traceback (most recent call last): 
    File "/app/module.py", line 135, in _process_web_service_call 
    request = u'<?xml version="1.0" encoding="utf-8"?>\n' + ET.tostring(root, encoding='utf-8') 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 137: ordinal not in range(128) 

這裏的137位對應於內部XML請求中的特殊字符的位置。顯然,即使給出編碼,cElementTree.tostring()也會返回'str'類型,而不是'unicode'。所以Python試圖將這個字符串str解碼爲unicode(爲什麼用'ascii'?),以便它可以將它與unicode文字連接起來。這失敗了(當然,因爲str實際上是用UTF-8編碼的,而不是ASCII編碼)。

所以我想,好,我會對其進行解碼爲Unicode自己則:,它吹起來的泡沫裏面,它試圖爲某些原因解碼外XML請求

root = ET.Element(u'ActionCommand') 
value = ET.SubElement(root, u'value') 
value.text = saxutils.escape(complex_value) 
request_encoded_str = ET.tostring(root, encoding='utf-8') 
request_unicode = request_encoded_str.decode('utf-8') 
request = u'<?xml version="1.0" encoding="utf-8"?>\n' + request_unicode 
client.service.ProcessClientAction(request) 

只是現在:

Traceback (most recent call last): 
    File "/app/module.py", line 141, in _process_web_service_call 
    raw_response = client.service.ProcessAction(request) 
    File "/app/.heroku/python/lib/python2.7/site-packages/suds/client.py", line 542, in __call__ 
    return client.invoke(args, kwargs) 
    File "/app/.heroku/python/lib/python2.7/site-packages/suds/client.py", line 602, in invoke 
    result = self.send(soapenv) 
    File "/app/.heroku/python/lib/python2.7/site-packages/suds/client.py", line 643, in send 
    reply = transport.send(request) 
    File "/app/.heroku/python/lib/python2.7/site-packages/suds/transport/https.py", line 64, in send 
    return HttpTransport.send(self, request) 
    File "/app/.heroku/python/lib/python2.7/site-packages/suds/transport/http.py", line 118, in send 
    return self.invoke(request) 
    File "/app/.heroku/python/lib/python2.7/site-packages/suds/transport/http.py", line 153, in invoke 
    u2response = urlopener.open(u2request, timeout=tm) 
    File "/app/.heroku/python/lib/python2.7/urllib2.py", line 404, in open 
    response = self._open(req, data) 
    File "/app/.heroku/python/lib/python2.7/urllib2.py", line 422, in _open 
    '_open', req) 
    File "/app/.heroku/python/lib/python2.7/urllib2.py", line 382, in _call_chain 
    result = func(*args) 
    File "/app/.heroku/python/lib/python2.7/urllib2.py", line 1222, in https_open 
    return self.do_open(httplib.HTTPSConnection, req) 
    File "/app/.heroku/python/lib/python2.7/urllib2.py", line 1181, in do_open 
    h.request(req.get_method(), req.get_selector(), req.data, headers) 
    File "/app/.heroku/python/lib/python2.7/httplib.py", line 973, in request 
    self._send_request(method, url, body, headers) 
    File "/app/.heroku/python/lib/python2.7/httplib.py", line 1007, in _send_request 
    self.endheaders(body) 
    File "/app/.heroku/python/lib/python2.7/httplib.py", line 969, in endheaders 
    self._send_output(message_body) 
    File "/app/.heroku/python/lib/python2.7/httplib.py", line 827, in _send_output 
    msg += message_body 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 565: ordinal not in range(128) 

此處的位置565再次與上述相同,除了這次是我的內部XML請求的位置嵌入由泡沫創建的外部XML請求(SOAP)中。

我很困惑。任何人都可以幫我解決這個問題嗎? :)

更糟的是,所有這些只發生在Linux下的服務器上。這些都不會在Windows上的開發環境中引發異常。 (關於爲什麼這樣說的附加說明,僅僅是因爲我很好奇,我懷疑它與不同的默認編碼有關。)但是,它們都不被服務器接受。如果我放棄saxutils.escape,然後將適當的unicode對象粘貼到泡沫上,Windows上的工作是什麼。但是,這仍然導致Linux上的相同UnicodeDecodeError

更新:我開始在Windows(其中正常工作)調試這一點,並在該行httplib.py的827,它的確試圖以連接unicode的對象msg(包含HTTP頭)和STR對象message_body,導致使用不正確編碼的隱式unicode解碼。我想這只是因爲某些原因在Windows上不會失敗。我不明白爲什麼suds試圖發送一個str對象時,我把一個unicode對象放在頂部。

回答

1

事實證明,這不僅僅是荒謬的。我仍然只理解整個問題和情況的一小部分,但我設法解決了我的問題。所以讓我們追溯一下:我相信,我最後一次嘗試是最理智的嘗試。因此,讓我們從這裏開始:

msg += message_body 

在Python的httplib.py嘗試來連接一個unicode和STR對象,這導致了海峽的隱.decode('ascii')那行,即使str是UTF8編碼。這是爲什麼?因爲msg是一個unicode對象。

msg = "\r\n".join(self._buffer) 

self._buffer是一個HTTP標頭列表。檢查一下,那裏只有一個頭是unicode,'感染'結果字符串:動作和終點。

還有問題:我使用unicode_literals__future__(使它更加面向未來,對嗎?),我將自己的端點傳遞給泡沫。

只要在網址上做一個.encode('utf-8'),我所有的問題都消失了。即使整個saxutils.escape已不再需要(即使它奇怪地也沒有受傷)。

tl; dr:確定你沒有將任何unicode對象傳遞到httplib或suds中,我想。

root = ET.Element(u'ActionCommand') 
value = ET.SubElement(root, u'value') 
value.text = complex_value) 
request = ET.tostring(root, encoding='utf-8').decode('utf-8') 
client.service.ProcessAction(request)