9

次のコードは安全ですか:

try {
    URL url = new URL(urlRequest);
    conn = (HttpURLConnection)url.openConnection();
    conn.setConnectTimeout(30000);
    conn.setReadTimeout(30000);
    conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
    String encoding = conn.getContentEncoding();
    return Utils.wrapCompressedStream(conn.getInputStream(), encoding);
} catch (IOException e) {
    if(conn != null) {
        conn.getContentEncoding();
        conn.getErrorStream();
        conn.whateverOtherMethodThere();
        ...
    }
}

特に、InterruptedIOException (読み取りタイムアウトなど) が発生した場合に、次のようなメソッドを呼び出すのは安全getContentEncoding()ですか? 私が理解している限り、この方法では HTTP(S) ヘッダーを読み取るためにライブ接続が必要です。

更新 (追加情報):

この質問は、実際のシステムでの経験に由来します。当時、システムは Oracle/Sun JVM 1.6 で実行されていたと思います。コードはほとんど同じです:

...    
} catch (IOException e) {
    if(conn != null) {
         try {
             String response = tryGetResponse(conn);
...

HTTPSリクエストtryGetResponseで問題が発生しました。

 private static String tryGetResponse(HttpURLConnection conn) {
    if(conn == null) return "(failed to get)";
    InputStream in = null;
    try {
        InputStream err = conn.getErrorStream();
        if (err != null) {
            in = Utils.wrapCompressedStream(err, conn.getContentEncoding());
        }
        return Utils.inputStreamToString(in);
    } catch (IOException e) {
        return "(failed to get)";
    } finally {
        Utils.closeQuitely(in);
    }
}

getContentEncoding()呼び出し中のソケット接続 (または読み取り) でシステムが自然にハングアップしました。

in = Utils.wrapCompressedStream(err, conn.getContentEncoding());

SocketTimeoutException初期コードでスローされた直後。

そのため、getContentEncoding()タイムアウトを設定せずに新しい接続を確立しようとする (または Java 6 で試行した) ようです。

4

4 に答える 4

3

いいえ、一般的に安全ではありません。動作は JVM 実装間で異なり (IBM J9 と Oracle VM と Open JDK を考えてください)、同じ VM のバージョン間で予告なしに変更される場合があります。

これは、API 仕様が保証しないためです。

使用している特定のバージョンの特定の実装を教えていただければ、ソースを調べて結論を出すことができます。しかし、そこで見つけた行動に頼らないよう強くお勧めします。

HTTP Sに関して: SSL にはまだいくつかのバグがあるようです。たとえば、OpenSSL は、セキュリティ バグを今週末に明らかにすると公に発表しました。そのバグ修正により、一部のエラー ケースでの HTTPS 接続の動作が変わる可能性があります。ソースで見つけたものは何でも、今週末には意味がなくなる可能性があります. そうでない場合は、次のセキュリティ修正で変更される可能性があります。

アップデート:

更新された質問で参照した Java のバージョンに対応するソースを見つけようとしました。Java ソースを見つけることは大きな問題ではありませんが、コードはすぐにネイティブ部分に入ります。これだけでも、答えがバージョン固有であるだけでなく、プラットフォーム固有 (Linux、Windows、Mac など) であるという良いヒントになります。Windows のネットワーク スタックなど、 Java 1.6 の OpenJDK ソースを自分で確認できます。

注意: Sun JDK 1.6 を使用している可能性が非常に高いです。OpenJDK 1.6 は Sun/Oracle JDK に基づいていますが、JDK 1.7 に基づいています。Open JDK 1.6 は、Sun/Oracle JDK 1.7 を Java 1.6 に移植したコード形式です。したがって、エラーが発生した後の接続の使用に関しては、まだいくつかの小さな違いがある可能性があります。

于 2015-03-17T09:39:54.403 に答える
2

仕様についてgetErrorStreamは次のように述べています。

接続に失敗したにもかかわらずサーバーが有用なデータを送信した場合は、エラー ストリームを返します。典型的な例は、HTTP サーバーが 404 で応答する場合です。これにより、Connect で FileNotFoundException がスローされますが、サーバーは何をすべきかについての提案を含む HTML ヘルプ ページを送信します。このメソッドでは、接続が開始されません。接続が接続されていない場合、または接続中にサーバーでエラーが発生しなかった場合、またはサーバーでエラーが発生したがエラー データが送信されなかった場合、このメソッドは null を返します。これがデフォルトです。

戻り値: ある場合はエラー ストリーム、エラーがない場合は null、接続が接続されていない場合、またはサーバーが有用なデータを送信していない場合。

ソースを調べて疑問を解消することもできるので、いくつかの方法を見てみましょう。

public InputStream getErrorStream() {
    if (connected && responseCode >= 400) {
        // Client Error 4xx and Server Error 5xx
        if (errorStream != null) {
            return errorStream;
        } else if (inputStream != null) {
            return inputStream;
        }
    }
    return null;
}

これを呼び出しても安全で (例外はスローされません)、場合によってerrorStreamは を設定できますIOException。ソースのコメントはbuffer the error stream if bytes < 4k and it can be buffered within 1 second.

getContentEncoding仕様からの動作は次のとおりです。

戻り値: URL が参照するリソースのコンテンツ エンコーディング、または不明な場合は null。

しかし、エラーの後はどうでしょうか? コードを見てみましょう:

public String getContentEncoding() { //from the base class java.net.URLConnection
    return getHeaderField("content-encoding");
}

public String getHeaderField(String name) {
    try {
        getInputStream();
    } catch (IOException e) {} //ah exception is eaten

    if (cachedHeaders != null) {
        return cachedHeaders.findValue(name);
    }

    return responses.findValue(name);
}

そのため、ヘッダーをキャッシュし、既知の場合はそれらを返します。潜在的にIOException.

于 2015-03-17T08:52:35.777 に答える
2

特に、InterruptedIOException(読み取りタイムアウトなど)の場合に次のようなメソッドを呼び出すのは安全ですかgetContentEncoding()?

あなたが試すことができます。たとえば、エラー ページの内容を呼び出して読み取ることIOException.は完全に安全です。IOException,FileNotFoundException,getErrorStream()

于 2015-03-17T08:53:52.320 に答える
0
catch (IOException e) {
    if(conn != null) {
        conn.getContentEncoding();
        conn.getErrorStream();
        conn.whateverOtherMethodThere();
        ...
    }

public class InterruptedIOException extends IOException

I/O 操作が中断されたことを通知します。InterruptedIOException は、実行中のスレッドが中断されたために入力または出力転送が終了したことを示すためにスローされます。フィールド bytesTransferred は、中断が発生する前に正常に転送されたバイト数を示します。

つまり、中断された例外が発生した場合、HttpUrlConnection でそれ以上の処理を行うことはできません。

繰り返しになりますが、IOException を使用すると、IllegalArgumentException、inlegalthreadstate 例外など、他の種類の例外をキャッチできません。

詳細についてはhttp://download.java.net/jdk7/archive/b123/docs/api/java/net/HttpURLConnection.html#getRequestMethod%28%29

于 2014-01-22T15:54:05.410 に答える