2011-11-03 1 views
6

Python 2.7에서 Pivotal Tracker API 모듈을 구현했습니다. Pivotal Tracker API은 POST 데이터가 XML 문서이고 "application/xml"이 컨텐트 유형이라고 예상합니다. 같이콘텐츠 유형이 "application/xml"인 경우 httplib를 사용하여 비 ASCII 문자를 게시하는 방법

내 코드는 문서를 게시 할 urlib/HTTPLIB 사용으로 근처에 내가 할 수있는

File "/usr/lib/python2.7/httplib.py", line 951, in endheaders 
    self._send_output(message_body) 
File "/usr/lib/python2.7/httplib.py", line 809, in _send_output 
    msg += message_body 
exceptions.UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 89: ordinal not in range(128) 

을 : XML 텍스트에 비 ASCII 문자가 포함 된 경우

request = urllib2.Request(self.url, xml_request.toxml('utf-8') if xml_request else None, self.headers) 
    obj = parse_xml(self.opener.open(request)) 

이 예외를 산출 httplib._send_output은 메시지 페이로드에 대한 ASCII 문자열을 생성합니다. 이는 아마도 데이터가 URL 인코딩 된 것으로 예상하기 때문입니다 (application/x-www-form-urlencoded). ASCII 문자 만 사용되는 한 application/xml에서 잘 작동합니다.

비 ASCII 문자가 포함 된 애플리케이션/xml 데이터를 게시하거나 (예 : Twistd 및 POST 페이로드에 맞춤 제작자를 사용하여) 농구를 뛰어 넘어야할까요?

답변

7

유니 코드와 바이트 코드를 혼합하고 있습니다.

self.headers = dict((k.encode('ascii') if isinstance(k, unicode) else k, 
        v.encode('ascii') if isinstance(v, unicode) else v) 
        for k,v in self.headers.items()) 

참고 : 헤더의 문자 인코딩 할 수 없다

>>> msg = u'abc' # Unicode string 
>>> message_body = b'\xc5' # bytestring 
>>> msg += message_body 
Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 0: ordinal \ 
not in range(128) 

것은 확실 self.headers 내용이 제대로 인코딩되어 즉,을,이 문제를 해결하려면, 모든 키는 headers의 값은 bytestrings해야 본문의 문자 인코딩 즉, xml 텍스트는 독립적으로 인코딩 될 수 있습니다 (HTTP 메시지의 관점에서 볼 때 옥텟 스트림입니다).

에 대해서는 unicode 유형이 있습니다. 그것을 ('ascii'문자 인코딩을 사용하는) bytestring으로 변환하십시오. 그래서 self.headers이 헤더에 사용되는


HTTP message consists of a start-line, "headers", an empty line and possibly a message-body, self.url는 (HTTP 메소드가 간다) 시작 라인에 사용되며 (클라이언트가 HTTP/1.1 인 경우) 아마에 대한 Host HTTP 헤더, XML 문자 (메시지 본문에 간다 바이너리 블롭으로).

self.url (ASCII가 아닌 도메인 이름의 경우 IDNA을 사용할 수 있습니다. 결과는 ASCII 임)에는 항상 ASCII 인코딩을 사용하는 것이 안전합니다. 여기

은 무엇 rfc 7230 says about http headers character encoding :

역사적으로, HTTP는 [RFC2047의 사용을 통해 다른 문자 집합을 지원의 ISO-8859-1 문자 세트 [ISO-8859-1] 텍스트 필드의 콘텐츠 허용했다 ] 인코딩. 실제로 대부분의 HTTP 헤더 필드 값은 US-ASCII 문자 세트 [USASCII]의 하위 집합 만 사용합니다. 새로 정의 된 헤더 필드는 필드 값을 US-ASCII 옥텟으로 제한해야합니다. 수신자는 내용 (obs-text) 필드의 다른 옥텟을 불투명 한 데이터로 취급해야합니다 (SHOULD).

가 bytestring에 XML을 변환하려면 application/xml encoding condsiderations를 참조하십시오

UTF-8을 사용하는 BOM없이, 모든 XML MIME 엔티티을 권장합니다.

+0

아마도 '내용 유형'을 변경할 수는 있지만 문제가 어떻게 해결 될까요? 'msg'는 파이썬 라이브러리에서 생성되고 바이트 문자열입니다. – jro

+1

@jro : HTTP와는 아무런 관련이 없습니다. 위의 * 완전한 * 예제를보십시오. – jfs

+0

이것이 문제의 원인이되었지만,'msg' 변수를 제어 할 수 없다는 것이 었습니다. 나는 당신의 요점에 동의하지만, 내 질문은 libs'msg'가'msg = "\ r \ n".join (self._buffer)로 생성 될 때 어떻게이 사실이 그를 해결할 수 있도록 도와 줄 수 있는지에 관한 것입니다. '? – jro

2

self.url이 유니 코드인지 확인하십시오. 유니 코드 인 경우 httplib은 유니 코드로 데이터를 처리합니다.

당신이 유니 코드로 인코딩 self.url을 강제 할 수 다음 HTTPLIB는 유니 코드로 모든 데이터를 처리합니다

0

여기

  • 비 유니 코드 문자열 + 유니 코드 문자열

      , 결과가됩니다 적용 할 3 가지 자동으로 유니 코드 문자열로 변환됩니다.
    • 파이썬 2.7 httplib, 단순히 +를 사용하여 머리말을 본문과 결합하는 것이 좋다고 생각하지 않습니다. 자동 유형 변환을 신뢰하면 안됩니다. 파이썬 2.6의 httplib은 다르다.
    • HTTP 프로토콜 표준 헤더 ISO-8859-1 인코딩을 제안하지만 비 ISO-8859-1 문자를 넣어하려는 경우, 당신은 설명 rfc2047로 인코딩해야

    간단한에게 솔루션은 발송하기 전에 헤더와 본문을 모두 utf-8로 엄격하게 인코딩하는 것입니다.

  • 1

    JF 세바스찬 응답과 동일하지만, 나는 새로운 하나를 추가 해요 그래서 작품을 서식 코드 (그리고 더 - 구글 수)

    다음

    당신의 마지막에 태그를 시도하는 경우 발생하는 상황 기계화 양식 요청 :

    br = mechanize.Browser() 
    br.select_form(nr=0) 
    br['form_thingy'] = u"Wonderful" 
    headers = dict((k.encode('ascii') if isinstance(k, unicode) else k, v.encode('ascii') if isinstance(v, unicode) else v) for k,v in br.request.headers.items()) 
    br.addheaders = headers 
    req = br.submit() 
    
    관련 문제