2014-01-23 1 views
6

Я пытаюсь портировать сценарий Python 3, который представляет XML-каналы здесь:BadStatusLine исключение возникает при возвращении ответа от сервера в Python 3

https://developers.google.com/search-appliance/documentation/files/pushfeed_client.py.txt

После запуска 2to3.py и сделать несколько незначительных корректировки, чтобы удалить любые синтаксические ошибки скрипта терпит неудачу с этим:

(py33dev) d:\dev\workspace>python pushfeed_client.py --datasource="TEST1" --feedtype="full" --url="http://gsa:19900/xmlfeed" --xmlfilename="test.xml" 
Traceback (most recent call last): 
    File "pushfeed_client.py", line 108, in <module> 
    main(sys.argv) 
    File "pushfeed_client.py", line 56, in main 
    result = urllib.request.urlopen(request_url) 
    File "C:\Python33\Lib\urllib\request.py", line 156, in urlopen 
    return opener.open(url, data, timeout) 
    File "C:\Python33\Lib\urllib\request.py", line 469, in open 
    response = self._open(req, data) 
    File "C:\Python33\Lib\urllib\request.py", line 487, in _open 
    '_open', req) 
    File "C:\Python33\Lib\urllib\request.py", line 447, in _call_chain 
    result = func(*args) 
    File "C:\Python33\Lib\urllib\request.py", line 1268, in http_open 
    return self.do_open(http.client.HTTPConnection, req) 
    File "C:\Python33\Lib\urllib\request.py", line 1253, in do_open 
    r = h.getresponse() 
    File "C:\Python33\Lib\http\client.py", line 1147, in getresponse 
    response.begin() 
    File "C:\Python33\Lib\http\client.py", line 358, in begin 
    version, status, reason = self._read_status() 
    File "C:\Python33\Lib\http\client.py", line 340, in _read_status 
    raise BadStatusLine(line) 
http.client.BadStatusLine: <!DOCTYPE html> 

Почему это возвращение, что исключение из ответа сервера? Вот полный ответ GSA, когда я понюхал сессию:

<!DOCTYPE html> 
<html lang=en> 
    <meta charset=utf-8> 
    <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width"> 
    <title>Error 400 (Bad Request)!!1</title> 
    <style> 
    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}} 
    </style> 
    <a href=//www.google.com/><img src=//www.google.com/images/errors/logo_sm.gif alt=Google></a> 
    <p><b>400.</b> <ins>That’s an error.</ins> 
    <p>Your client has issued a malformed or illegal request. <ins>That’s all we know.</ins> 

И это было возвращать HTTP 400. Я могу надежно вызвать этот вопрос всякий раз, когда полезная нагрузка XML имеет характер UTF-8 в нем. Он работает безупречно, когда это простой ascii. Вот самые основные версии кода я могу использовать, чтобы надежно воссоздать проблему:

import http.client 
http.client.HTTPConnection.debuglevel = 1 
with open("GSA_full_Feed.xml", encoding='utf-8') as xdata: 
    payload = xdata.read() 
content_length = len(payload) 
feed_path = "xmlfeed" 
content_type = "multipart/form-data; boundary=----------boundary_of_feed_data$" 
headers = {"Content-type": content_type, "Content-length": content_length} 
conn = http.client.HTTPConnection("gsa", 19900) 
conn.request("POST", feed_path, body=payload.encode("utf-8"), headers=headers) 
res = conn.getresponse() 
print(res.read()) 
conn.close() 

А вот полезная нагрузка образец XML, который используется, чтобы вызвать исключение:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE gsafeed PUBLIC "-//Google//DTD GSA Feeds//EN" "gsafeed.dtd"> 
<gsafeed> 
    <header> 
    <datasource>TEST1</datasource> 
    <feedtype>full</feedtype> 
    </header> 
    <group> 
    <record action="add" mimetype="text/html" url="https://myschweetassurl.com"> 
     <metadata> 
     <meta content="shit happens, then you die" name="description"/> 
     </metadata> 
     <content>wacky Umläut test of non utf-8 characters</content> 
    </record> 
    </group> 
</gsafeed> 

только дельта я могу найти между версиями 2 и 3 являются заголовками длины содержимого для каждого запроса. Версия Python 3 последовательно короче, чем версия 2, 870 по сравнению с 873.

ответ

7

После множества проводов мы выяснили причину и решение проблемы в том, как задан заголовок длины контента. В моем порт Python 3 скрипта я скопировал метод, который задал длину содержимого. Что это:

headers['Content-length']=str(len(body)) 

Это неверно! Правильный способ заключается в следующем:

headers['Content-length']=str(len(bytes(body, 'utf-8'))) 

Поскольку полезная нагрузка должна быть байтовым объектом. Когда вы кодируете байты, длина отличается от строковой.

return urllib.request.Request(theurl, bytes(body, 'utf-8'), headers) 

Вы можете безопасно опустить вручную устанавливая заголовок длины содержимого при использовании ничего, производный от http.client.HTTPConnection. Он имеет внутренний метод, который проверяет заголовок длины содержимого, и если он отсутствует, установите его на основе длины тела содержимого независимо от формы.

Проблема была перевода, но тонкой разницы между Python 2 и 3 и того, как она обрабатывает строки и кодирует их. Должно быть, это была какая-то случайность, когда обычная версия ASCII работала, когда версия utf-8 не была, ну ладно.