2011-11-03 12 views
6

पर पाइथन 2.7 में एक पिवोटल ट्रैकर एपीआई मॉड्यूल लागू किया है, तो मैंस्पेलप्लिब का उपयोग करके गैर-ASCII वर्णों को कैसे पोस्ट करूं? Pivotal Tracker API पोस्ट डेटा को XML प्रकार और "एप्लिकेशन/एक्सएमएल" सामग्री प्रकार होने की अपेक्षा करता है।जब मैं सामग्री-प्रकार "एप्लिकेशन/एक्सएमएल"

मेरे कोड का उपयोग करता urlib/httplib दस्तावेज़ पोस्ट करने के लिए दिखाया गया है:

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

यह एक अपवाद पैदावार जब एक्सएमएल पाठ गैर- ASCII वर्ण हैं:

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) 

के रूप में पास के रूप में मैं कर सकते हैं देखें, httplib._send_output संदेश पेलोड के लिए एक ASCII स्ट्रिंग बना रहा है, संभवतः क्योंकि यह डेटा को यूआरएल एन्कोडेड (एप्लिकेशन/एक्स-www-form-urlencoded) होने की अपेक्षा करता है। जब तक केवल ASCII वर्णों का उपयोग नहीं किया जाता है तब तक यह एप्लिकेशन/एक्सएमएल के साथ ठीक काम करता है।

क्या गैर-ASCII वर्ण वाले एप्लिकेशन/एक्सएमएल डेटा पोस्ट करने का एक सीधा तरीका है या क्या मुझे हुप्स के माध्यम से कूदना होगा (उदाहरण के लिए ट्विस्टड और पोस्ट पेलोड के लिए कस्टम निर्माता) का उपयोग करना होगा?

उत्तर

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 संदेश के दृष्टिकोण से एक ऑक्टेट स्ट्रीम है)।

यह self.url के लिए जाता है - यदि इसमें unicode प्रकार है; इसे एक बाइटस्ट्रिंग में परिवर्तित करें ('ascii' वर्ण एन्कोडिंग का उपयोग करके)।


HTTP message consists of a start-line, "headers", an empty line and possibly a message-body तो self.headers हेडर के लिए प्रयोग किया जाता है, self.url शुरू लाइन के लिए प्रयोग किया जाता है (http विधि यहाँ जाता है) और शायद के लिए Host http हैडर (अगर ग्राहक http/1.1 है), एक्सएमएल पाठ संदेश के शरीर में चला जाता है (बाइनरी ब्लॉब के रूप में)।

यह हमेशा self.url के लिए ASCII एन्कोडिंग का उपयोग करने के लिए सुरक्षित (IDNA गैर- ASCII डोमेन के लिए इस्तेमाल किया जा सकता नामों-परिणाम है भी ASCII) है।

यहाँ क्या rfc 7230 says about http headers character encoding:

ऐतिहासिक रूप से, HTTP ISO-8859-1 चारसेट [ISO-8859-1] में पाठ के साथ क्षेत्र की सामग्री की अनुमति दी है, केवल [RFC2047 के उपयोग के माध्यम से अन्य वर्णसेट समर्थन ] एन्कोडिंग। व्यावहारिक रूप से, अधिकांश HTTP शीर्षलेख फ़ील्ड मान केवल यूएस-एएससीआईआईआई वर्णसेट [यूएसएएससीआईआईआई] का एक सबसेट उपयोग करते हैं। नए परिभाषित हेडर फ़ील्ड्स को अपने फ़ील्ड मानों को यूएस-एएससीआईआई ऑक्टेट्स तक सीमित करना चाहिए। प्राप्तकर्ता को अन्य octets को सामग्री (ऑब्जेक्ट-टेक्स्ट) में अपारदर्शी डेटा के रूप में देखना चाहिए।

एक bytestring करने के लिए XML बदलने के लिए, application/xml encoding condsiderations देखें:

UTF-8 का उपयोग करते हैं, एक बीओएम के बिना, सभी XML माइम संस्थाओं के लिए सिफारिश की है।

+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 प्रेजेंटप्लिब, शरीर के साथ शीर्षलेख में शामिल होने के लिए + का उपयोग करता है जो मुझे नहीं लगता कि यह एक अच्छा अभ्यास है, हमें स्वचालित प्रकार के रूपांतरण पर भरोसा नहीं करना चाहिए। लेकिन पायथन 2.6 fansplib अलग है।
  • HTTP प्रोटोकॉल मानक चलता है हेडर के लिए ISO-8859-1 एन्कोडिंग, लेकिन अगर आप गैर ISO-8859-1 पात्रों रखना चाहते हैं, तो आप इसे सांकेतिक शब्दों में बदलना करने के लिए rfc2047 के रूप में वर्णित है

सरल समाधान भेजने से पहले utf-8 दोनों में हेडर और बॉडी दोनों को सख्ती से एन्कोड करना है। जेएफ सेबस्टियन जवाब के रूप में

1

एक ही है, लेकिन मैं एक नया जोड़ने रहा हूँ तो कोड स्वरूपण काम करता है (और है अधिक गूगल करने योग्य)

यहाँ क्या हुआ अगर आप के अंत तक पर टैग करने के लिए कोशिश कर रहे हैं क्या होता है एक मशीनीकरण फॉर्म अनुरोध:

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()