質問: Apache HttpClient 4.xは、より大きいファイルをアップロードするときに奇妙な動作をしますか? 私は、Java(およびscala)を使用して、少しストレートなクライアント/サーバーアプリケーションを開発し、テストしています。 **サーバー**は、 `com.sun.net.httpserver.HttpServer` に基づいており、POSTおよびPUT操作を使用して基本的なRESTfulインターフェイス経由でファイルをアップロードできます。アップロード操作は、Googleが独自に実装したダイジェスト認証を使用して制限されています。ブラウザ、カール、および `Apache HttpClient` をクリックします。 **クライアントをアップロード**すると `Apache HttpClient 4.1.2` がラップされ、ファイルエンティティをアップロードするためにhttp経由でPUT操作が実行されます。ファイルのコンテンツタイプはヘッダーに `application/xml` として指定され、一度に1つのファイルのみがアップロードされます。 **さまざまなサイズのファイル**をアップロードすると、奇妙な動作が観察されることがあります: * サイズが1.076.006バイト以下のファイルがアップロードされます **正常**: * サイズが1.122.158バイト以上のファイル `java.net.SocketException:壊れたパイプで**失敗**します。` `(*最大作業サイズに近似するように異なるサイズのファイルを手動で作成したため、正確なクリティカルサイズは不明です*) 破損したパイプの理由は、**クライアントがサーバーログで文書化されているように、 `www-authenticate` レスポンス**をアップロードしたファイルを無視したためです。 「無視」とは、認証ヘッダーを一切含まない複数のメッセージを送信するという意味です。 しかし、*より小さいファイル*がうまく動作し、クライアントは `www-authenticate` レスポンスの直後に正しいchallenge-responseを持つ認証要求を正しく送信します。 **アップロードはすべてのサイズのファイルでカールしているので、問題はありません。** だからこの時点で、あなたのクライアントにはいくつかのバグがあります。わかりました。しかし、私は親切ですが、**オープンソースのJavaを試しました。 RESTclient** (これはapache httpclientもラップしています)、同じ動作を*正確に*持っています! 私たちはインターネット上でこのクライアントを使って試してみました。だから今、私は、この誤った振る舞いにつながる `Apache HttpClient` に何か重要なものを置くことを忘れてしまい、オープンソースのRESTクライアントの開発者がそれを見逃してしまったのではないかと思います。それは素晴らしいだろう!`
回答: ほとんどの場合、この状況につながるいくつかの要素の組み合わせです (1)認証ヘッダーを含まないリクエストで大量のリクエストエンティティを送信するときに、クライアントが 'expect-continue'ハンドシェイクを使用しない可能性があります。 (2)サーバは、リクエストが期待通りに失敗したことを早期に検出し、フルのリクエストボディを読み込んで破棄するのではなく、401ステータスで早期に応答し、最後に接続を閉じます。私の意見では、これはサーバー側のHTTPプロトコル違反です。 (3)一部のHTTPエージェントは早期の応答に対処できますが、Apache HttpClientはJavaブロッキングI/O(実行スレッドはブロッキングソケットから読み書きできますが、両方ではありません)の制限のためにできません。 問題を解決するには複数の方法がありますが、「最も期待している」ハンドシェイクは最も簡単で最も自然なものです。代わりに、簡単なHEADまたはGET要求を実行して、大きなPOSTまたはPUT要求を実行する前にHTTP認証を強制することもできます。 HttpClientは、同じ論理HTTPセッションで後続の要求に認証データを再利用することができます。