7

Python 2.7 で Pivotal Tracker API モジュールを実装しました。Pivotal Tracker APIは、POST データが XML ドキュメントであり、「application/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))

これにより、XML テキストに非 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 文字列を作成しています。ASCII 文字のみが使用されている限り、application/xml で問題なく動作します。

ASCII 以外の文字を含むアプリケーション/xml データをポストする簡単な方法はありますか?それともフープを飛び越える必要がありますか?

4

4 に答える 4

8

Unicode とバイト文字列を混在させています。

>>> 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必要があります。

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

注: ヘッダーの文字エンコーディングは、本文の文字エンコーディングとは関係ありません。つまり、xml テキストは個別にエンコードできます (http メッセージの観点からは単なるオクテット ストリームです)。

同じself.urlことが、unicode型がある場合にも当てはまります。バイト文字列に変換します (「ascii」文字エンコーディングを使用)。


HTTP メッセージは、開始行、「ヘッダー」、空の行、および場合によってはメッセージ本文で構成されるためself.headers、ヘッダーにself.url使用され、開始行 (http メソッドがここに入る) に使用され、おそらくHosthttp ヘッダー (クライアントが http の場合) に使用されます。 /1.1)、XML テキストはメッセージ本文に入れられます (バイナリ BLOB として)。

ASCII エンコーディングを使用することは常に安全ですself.url(非 ASCII ドメイン名には IDNA を使用できます。結果も ASCII になります)。

HTTPヘッダーの文字エンコーディングについてrfc 7230が述べていることは次のとおりです。

歴史的に、HTTP は ISO-8859-1 文字セット [ISO-8859-1] のテキストを含むフィールド コンテンツを許可しており、[RFC2047] エンコーディングを使用することによってのみ他の文字セットをサポートしています。実際には、ほとんどの HTTP ヘッダー フィールド値は、US-ASCII 文字セット [USASCII] のサブセットのみを使用します。新しく定義されたヘッダー フィールドは、フィールド値を US-ASCII オクテットに制限する必要があります。受信者は、フィールド コンテンツ (obs-text) の他のオクテットを不透明なデータとして扱う必要があります (SHOULD)。

XML をバイト文字列に変換するには、application/xmlエンコードに関する考慮事項を参照してください。

BOM なしの UTF-8 の使用は、すべての XML MIME エンティティに対して推奨されます。

于 2011-11-03T10:31:06.970 に答える
2

self.urlがユニコードかどうかを確認します。Unicode の場合はhttplib、データを Unicode として扱います。

self.url を Unicode に強制的にエンコードすると、httplib はすべてのデータを Unicode として扱います。

于 2013-06-09T06:30:31.933 に答える
0

ここで取り上げる内容は 3 つあります

  • 非 Unicode 文字列 + Unicode 文字列の場合、結果は自動的に Unicode 文字列に変換されます。
  • Python 2.7 httplib では、単に + を使用してヘッダーと本文を結合するだけですが、これは良い方法ではないと思います。自動型変換を信頼するべきではありません。しかし、Python 2.6 httplib は異なります。
  • HTTP プロトコル標準では、ヘッダーの ISO-8859-1エンコーディングが推奨されていますが、 ISO-8859-1以外の文字を入れたい場合は、 rfc2047で説明されているようにエンコードする必要があります

簡単な解決策は、送信する前にヘッダーと本文の両方を utf-8 に厳密にエンコードすることです。

于 2015-07-04T10:20:52.593 に答える