5

curlをPythonとrequestsライブラリに置き換えようとしています。curlを使用すると、curl-Tオプションを使用して単一のXMLファイルをRESTサーバーにアップロードできます。私はリクエストライブラリで同じことをすることができませんでした。

基本的なシナリオは機能します:

payload = '<person test="10"><first>Carl</first><last>Sagan</last></person>'
headers = {'content-type': 'application/xml'}
r = requests.put(url, data=payload, headers=headers, auth=HTTPDigestAuth("*", "*"))

XMLファイルを開いてペイロードをより大きな文字列に変更すると、.putメソッドがハングします(コーデックライブラリを使用して適切なUnicode文字列を取得します)。たとえば、66KBのファイルの場合:

xmlfile = codecs.open('trb-1996-219.xml', 'r', 'utf-8')
headers = {'content-type': 'application/xml'}
content = xmlfile.read()
r = requests.put(url, data=content, headers=headers, auth=HTTPDigestAuth("*", "*"))

マルチパートオプション(ファイル)の使用を検討してきましたが、サーバーはそれを好まないようです。

そのため、Pythonリクエストライブラリでcurl-Tの動作をシミュレートする方法があるかどうか疑問に思いました。

更新1:プログラムはtextmateでハングしますが、コマンドラインでUnicodeEncodeErrorエラーをスローします。それが問題のようです。したがって、質問は次のようになります。リクエストライブラリを使用してサーバーにUnicode文字列を送信する方法はありますか?

更新2:Martijn Pietersのコメントのおかげで、UnicodeEncodeErrorはなくなりましたが、新しい問題が発生しました。リテラル(ASCII)XML文字列の場合、ロギングには次の行が表示されます。

2012-11-11 15:55:05,154 INFO Starting new HTTP connection (1): my.ip.address
2012-11-11 15:55:05,294 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 401 211
2012-11-11 15:55:05,430 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 201 0

サーバーは常に最初の認証試行(?)をバウンスしますが、2回目の認証試行を受け入れます。

ファイルオブジェクト(open('trb-1996-219.xml'、'rb'))がデータに渡されると、ログファイルには次のように表示されます。

2012-11-11 15:50:54,309 INFO Starting new HTTP connection (1): my.ip.address
2012-11-11 15:50:55,105 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 401 211
2012-11-11 15:51:25,603 WARNING Retrying (0 attempts remain) after connection broken by 'BadStatusLine("''",)': /v1/documents?uri=/example/test.xml

したがって、最初の試行は以前と同様にブロックされますが、2回目の試行は行われません。

Martijn Pieters(下記)によると、2番目の問題はサーバーの障害(空の回線)によって説明できます。私はこれを調べますが、誰かが(カールを使用することを除いて)回避策を持っているなら、私はそれを聞いてもかまいません。

そして、リクエストライブラリが小さな文字列とファイルオブジェクトに対して非常に異なる動作をすることに、私はまだ驚いています。とにかく、ファイルオブジェクトはサーバーに到達する前にシリアル化されていませんか?

4

3 に答える 3

9

大きなファイルをPUTするには、それらをメモリに読み込まないでください。ファイルをdataキーワードとして渡すだけです。

xmlfile = open('trb-1996-219.xml', 'rb')
headers = {'content-type': 'application/xml'}
r = requests.put(url, data=xmlfile, headers=headers, auth=HTTPDigestAuth("*", "*"))

さらに、ファイルをユニコードとして開いていました(UTF-8からデコード)。リモートサーバーに送信するため、Unicode値ではなく、rawバイトが必要であり、代わりにファイルをバイナリとして開く必要があります。

于 2012-11-11T14:01:11.637 に答える
1

ダイジェスト認証では、常にサーバーに対して少なくとも2つの要求を行う必要があります。最初のリクエストには認証データが含まれていません。この最初のリクエストは、401「認証が必要」の応答コードとパスワードのハッシュなどに使用されるダイジェストチャレンジ(nounceと呼ばれる)で失敗します(正確な詳細はここでは重要ではありません)。これは、チャレンジでハッシュされた資格情報を含む2番目のリクエストをサーバーに送信するために使用されます。

問題は、この2段階認証にあります。大きなファイルは最初の無許可の要求(無駄に送信)ですでに送信されていますが、2番目の要求ではファイルオブジェクトはすでにEOF位置にあります。ファイルサイズも2番目のリクエストのContent-lengthヘッダーで送信されたため、サーバーは送信されないファイルを待機します。

リクエストセッションを使用してそれを解決し、最初に認証目的で単純なリクエストを行うことができます(たとえばGETリクエスト)。次に、最初のリクエストと同じダイジェストチャレンジを使用して、実際のペイロードを含む2番目のPUTリクエストを作成します。

sess = requests.Session()
sess.auth = HTTPDigestAuth("*", "*")
sess.get(url)
headers = {'content-type': 'application/xml'}
with codecs.open('trb-1996-219.xml', 'r', 'utf-8') as xmlfile:
    sess.put(url, data=xmlfile, headers=headers)
于 2013-05-17T08:14:11.607 に答える
0

Pythonでリクエストを使用して、コマンドを使用してXMLファイルをアップロードしました。最初にファイルを開くには、open()を使用 file = open("PIR.xsd") fragment = file.read() file.close() して、リクエストのペイロードにあるXMLファイルのデータをコピーし、投稿し payload = {'key':'PFAkrzjmuZR957','xmlFragment':fragment} r = requests.post(URL,data=payload) てhtml検証コードを確認します。 print (r.text)

于 2018-07-24T11:09:08.403 に答える