web-dev-qa-db-ja.com

HttpURLConnectionの安全な使用

HttpURLConnectionを使用する場合、「取得」して使用しない場合はInputStreamを閉じる必要がありますか?

つまり、これは安全ですか?

HttpURLConnection conn = (HttpURLConnection) uri.getURI().toURL().openConnection();
conn.connect();
// check for content type I don't care about
if (conn.getContentType.equals("image/gif") return; 
// get stream and read from it
InputStream is = conn.getInputStream();
try {
    // read from is
} finally {
    is.close();
}

第二に、すべてのコンテンツが完全に読み込まれる前にInputStream を閉じることは安全ですか

基礎となるソケットをESTABLISHEDまたはCLOSE_WAIT状態のままにするリスクはありますか?

47
Joel

すべてのコンテンツが読み込まれる前にInputStreamを閉じても安全ですか?

基になるTCP接続がキャッシュされるようにするために、入力ストリームのすべてのデータを閉じる前に読み取る必要があります。最新のJavaでは必要ではないことを読みました接続の再利用のために応答全体を読み取ることが常に義務付けられています。

この投稿を確認してください: Java6でキープアライブ

28
Cratylus

http://docs.Oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html およびOpenJDKソースコードによると。

(_keepAlive == true_の場合)

クライアントがHttpURLConnection.getInputSteam().close()を呼び出した場合、後でHttpURLConnection.disconnect()を呼び出すと、Socketを閉じませんNOT。つまり、Socketは再利用されます(キャッシュされます)

クライアントがclose()を呼び出さない場合、disconnect()を呼び出すと、InputStreamが閉じられ、Socketが閉じられます。

したがって、Socketを再利用するには、InputStream.close()を呼び出すだけです。 HttpURLConnection.disconnect()を呼び出さないでください。

34
Anderson Mao

キープアライブキャッシュに関する情報を次に示します。この情報はすべて、Java 6に関連していますが、多くの以前および以降のバージョンでもおそらく正確です。

私が言えることから、コードは次のように要約されます:

  1. リモートサーバーが正の整数として解析できる「タイムアウト」値を持つ「キープアライブ」ヘッダーを送信する場合、その秒数がタイムアウトに使用されます。
  2. リモートサーバーが「キープアライブ」ヘッダーを送信したが、正の整数およびとして解析できる「タイムアウト」値がない場合「usingProxy」がtrueの場合、タイムアウトは60秒です。
  3. 他のすべての場合、タイムアウトは5秒です。

このロジックは、 Sun.net.www.http.HttpClient (「parseHTTPHeader」メソッド内)の725行目付近と Sun.net。 www.http.KeepAliveCache (「put」メソッド内)。


そのため、タイムアウト期間を制御するには2つの方法があります。

  1. リモートサーバーを制御し、適切なタイムアウトフィールドを持つキープアライブヘッダーを送信するように構成します
  2. JDKソースコードを変更し、独自にビルドします。

内部JDKクラスを再コンパイルせずに、明らかに任意の5秒のデフォルトを変更することは可能だと思うでしょうが、そうではありません。 bug は2005年にこの機能を要求するために提出されましたが、Sunはそれを提供することを拒否しました。

18

接続を確実に閉じたい場合は、conn.disconnect()を呼び出す必要があります。

開いた接続は、HTTP 1.1接続キープアライブ機能( HTTP Persistent Connections とも呼ばれます)が原因です。サーバーがHTTP 1.1をサポートし、応答ヘッダーでConnection: closeを送信しない場合Javaは、入力ストリームを閉じたときに、下にあるTCP接続をすぐに閉じません。代わりに、サーバーを開いたままにして、同じサーバーへの次のHTTP要求に再利用しようとします。

この動作がまったく必要ない場合は、システムプロパティhttp.keepAliveをfalseに設定できます。

System.setProperty("http.keepAlive","false");
7
Robert

HTTPリクエストが失敗した場合(200以外)、エラーストリームを閉じる必要もあります。

try {
  ...
}
catch (IOException e) {
  connection.getErrorStream().close();
}

これを行わないと、200を返さないリクエスト(タイムアウトなど)はすべて1つのソケットをリークします。

3
Vlad Lifliand

HttpURLConnectionを使用する場合、「取得」して使用しない場合はInputStreamを閉じる必要がありますか?

はい、常に閉じている必要があります。

つまり、これは安全ですか?

100%ではなく、NPEを取得するリスクがあります。より安全です:

InputStream is = null;
try {
    is = conn.getInputStream()
    // read from is
} finally {
    if (is != null) {
        is.close();
    }
}
1
Arjan Tijms