9

クライアントでマルチパート MIME http リクエストを作成し、サーバーで適切に解釈できる Python コードを作成しようとしています。私は、これでクライアント側で部分的に成功したと思います:

from email.mime.multipart import MIMEMultipart, MIMEBase
import httplib
h1 = httplib.HTTPConnection('localhost:8080')
msg = MIMEMultipart()
fp = open('myfile.zip', 'rb')
base = MIMEBase("application", "octet-stream")
base.set_payload(fp.read())
msg.attach(base)
h1.request("POST", "http://localhost:8080/server", msg.as_string())

これに関する唯一の問題は、電子メール ライブラリに Content-Type ヘッダーと MIME-Version ヘッダーも含まれていることです。httplib に含まれる HTTP ヘッダーとどのように関連するのかわかりません。

Content-Type: multipart/mixed; boundary="===============2050792481=="
MIME-Version: 1.0

--===============2050792481==
Content-Type: application/octet-stream
MIME-Version: 1.0

これが、このリクエストが web.py アプリケーションによって受信されたときに、エラー メッセージが表示される理由である可能性があります。web.py POST ハンドラー:

class MultipartServer:
    def POST(self, collection):
        print web.input()

このエラーをスローします:

Traceback (most recent call last):
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/application.py", line 242, in process
    return self.handle()
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/application.py", line 233, in handle
    return self._delegate(fn, self.fvars, args)
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/application.py", line 415, in _delegate
    return handle_class(cls)
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/application.py", line 390, in handle_class
    return tocall(*args)
  File "/home/richard/Development/server/webservice.py", line 31, in POST
    print web.input()
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/webapi.py", line 279, in input
    return storify(out, *requireds, **defaults)
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/utils.py", line 150, in storify
    value = getvalue(value)
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/utils.py", line 139, in getvalue
    return unicodify(x)
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/utils.py", line 130, in unicodify
    if _unicode and isinstance(s, str): return safeunicode(s)
  File "/usr/local/lib/python2.6/dist-packages/web.py-0.34-py2.6.egg/web/utils.py", line 326, in safeunicode
    return obj.decode(encoding)
  File "/usr/lib/python2.6/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 137-138: invalid data

私のコード行は、半分ほど下のエラー行で表されます。

  File "/home/richard/Development/server/webservice.py", line 31, in POST
    print web.input()

順調に進んでいますが、ここからどこへ行くべきかわかりません。これは私のクライアント コードの問題ですか、それとも web.py の制限 (おそらくマルチパート リクエストをサポートできないだけ) ですか? 代替コード ライブラリのヒントや提案をいただければ幸いです。

編集

上記のエラーは、データが自動的に base64 でエンコードされていないことが原因でした。追加する

encoders.encode_base64(base)

このエラーを取り除き、問題が明確になりました。HTTP リクエストがサーバーで正しく解釈されていません。おそらく、電子メール ライブラリの本文に HTTP ヘッダーであるべきものが含まれているためです。

<Storage {'Content-Type: multipart/mixed': u'', 
          ' boundary': u'"===============1342637378=="\n'
          'MIME-Version: 1.0\n\n--===============1342637378==\n'
          'Content-Type: application/octet-stream\n'
          'MIME-Version: 1.0\n' 
          'Content-Transfer-Encoding: base64\n'
          '\n0fINCs PBk1jAAAAAAAAA.... etc

そのため、何かが正しくありません。

ありがとう

リチャード

4

3 に答える 3

1

Will Holcomb http://pypi.python.org/pypi/MultipartPostHandler/0.1.0のこのパッケージを使用して、urllib2 でマルチパート リクエストを作成しました。

于 2010-12-14T01:20:27.137 に答える
1

少し調べてみると、この質問に対する答えが明らかになりました。簡単に言えば、Mime でエンコードされたメッセージでは Content-Disposition はオプションですが、web.py では HTTP リクエストを正しく解析するために各 MIME パーツに必要です。

この質問に関する他のコメントとは対照的に、HTTP と電子メールの違いは無関係です。これらは単に Mime メッセージのトランスポート メカニズムであり、それ以上のものではないからです。マルチパート/関連 (マルチパート/フォームデータではない) メッセージは、コンテンツ交換 Web サービスで一般的であり、ここでの使用例です。ただし、提供されたコード スニペットは正確であり、問​​題の解決策が少し簡潔になりました。

# open an HTTP connection
h1 = httplib.HTTPConnection('localhost:8080')

# create a mime multipart message of type multipart/related
msg = MIMEMultipart("related")

# create a mime-part containing a zip file, with a Content-Disposition header
# on the section
fp = open('file.zip', 'rb')
base = MIMEBase("application", "zip")
base['Content-Disposition'] = 'file; name="package"; filename="file.zip"'
base.set_payload(fp.read())
encoders.encode_base64(base)
msg.attach(base)

# Here's a rubbish bit: chomp through the header rows, until hitting a newline on
# its own, and read each string on the way as an HTTP header, and reading the rest
# of the message into a new variable
header_mode = True
headers = {}
body = []
for line in msg.as_string().splitlines(True):
    if line == "\n" and header_mode == True:
        header_mode = False
    if header_mode:
        (key, value) = line.split(":", 1)
        headers[key.strip()] = value.strip()
    else:
        body.append(line)
body = "".join(body)

# do the request, with the separated headers and body
h1.request("POST", "http://localhost:8080/server", body, headers)

これは web.py によって完全に適切に検出されるため、email.mime.multipart は、ヘッダー処理を除いて、HTTP によって転送される Mime メッセージの作成に適していることは明らかです。

私の他の全体的な懸念は、スケーラビリティです。このソリューションも、ここで提案されている他のソリューションも、MIME メッセージにまとめる前にファイルの内容を変数に読み込むため、うまく拡張できません。より良い解決策は、コンテンツが HTTP 接続を介してパイプアウトされるときにオンデマンドでシリアル化できるものです。それを修正することは私にとって緊急ではありませんが、解決策を見つけたらここに戻ってきます.

于 2010-12-21T22:11:33.753 に答える
-1

あなたの要求には多くの問題があります。TokenMacGuy が示唆するように、multipart/mixed は HTTP では使用されません。代わりに multipart/form-data を使用してください。さらに、パーツには Content-disposition ヘッダーが必要です。これを行うための Python フラグメントは、コード レシピにあります。

于 2010-12-13T23:14:27.553 に答える