4

Java(およびscala)を使用して、少し単純なクライアントサーバーアプリケーションを開発およびテストしています。

このサーバーcom.sun.net.httpserver.HttpServerは、POST および PUT 操作を使用した基本的な RESTful インターフェースを介したファイルのアップロードに基づいており、これを可能にします。アップロード操作は、独自に実装したダイジェスト認証を使用して制限されており、ブラウザー、curl Apache HttpClient、.

アップロード クライアントは、HTTP 経由で PUT 操作をラップApache HttpClient 4.1.2して実行し、ファイル エンティティをアップロードします。ファイルの content-type はapplication/xmlヘッダーのように指定され、一度に 1 つのファイルのみがアップロードされます。

異なるサイズのファイルをアップロードすると、奇妙な動作が観察される場合があります。

  • サイズが 1.076.006 バイト以下のファイルは 正常にアップロードされます。
  • サイズが1.122.158 バイト以上のファイルは 、java.net.SocketException: Broken pipe.

最大作業サイズを概算するために手動で異なるサイズのファイルを作成したため、正確な重要なサイズは不明です

壊れたパイプの理由は、サーバー ログに記録されているように、クライアントがそのサイズの-responseアップロード ファイルを何らかの形で無視したためです。www-authenticate「無視」とは、認証ヘッダーをまったく含まない複数 (4) のメッセージを送信することを意味します。しかし、より小さいファイルwww-authenticateはうまく機能し、クライアントは、本来あるべき応答の直後に、適切なチャレンジ応答を含む認証要求を送信します。

アップロードはすべてのサイズのファイルで curl で機能するため、問題はありません。

したがって、この時点で、「クライアントにバグがあります」と言うことができます。わかりました、そう願っていますが、オープンソースの Java RESTclient (Apache httpclient もラップ)も試してみましたが、まったく同じ動作をしています!

インターネット経由でこのクライアントを使用して試してみましたが、説明と同じです。だから今、私はApache HttpClientこの誤った動作につながる重要なものを設定し忘れていて、オープンソースの RESTclient の開発者もそれを見逃していたことを願っています...それが何であるかについてのアイデアは素晴らしいでしょう!

4

1 に答える 1

6

ほとんどの場合、この状況につながるのはいくつかの要因の組み合わせです

(1) 認証ヘッダーを含まないリクエストで大きなリクエスト エンティティを送信する場合、クライアントは「expect-continue」ハンドシェイクを使用しない可能性があります。

(2) サーバーは、リクエストが予期しないものであることを早期に検出し、完全なリクエスト本文を読み取って破棄する代わりに、401 ステータスで早期に応答し、最後に接続を閉じます。私の意見では、これはサーバー側の HTTP プロトコル違反です。

(3) 一部の HTTP エージェントは初期応答を処理できますが、Apache HttpClient は Java ブロッキング I/O の制限によりできません (実行スレッドはブロッキング ソケットから読み取りまたは書き込みのいずれかを実行できますが、両方は実行できません)。

この問題に対処するには複数の方法がありますが、'expect-continue' ハンドシェイクが最も簡単で自然な方法です。別の方法として、大きな POST または PUT 要求を実行する前に、単純な HEAD または GET 要求を実行して HTTP 認証を強制することもできます。HttpClient は、同じ論理 HTTP セッション内の後続の要求で認証データを再利用できます。

于 2012-02-07T12:40:32.337 に答える