HttpURLConnectionタイムアウト設定


123

URLの接続に5秒以上かかる場合にfalseを返したいのですが、Javaを使用してこれをどのように行うことができますか?URLが有効かどうかを確認するために使用しているコードは次のとおりです

HttpURLConnection.setFollowRedirects(false);
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("HEAD");
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);

回答:


201

HttpURLConnection持っているsetConnectTimeoutの方法を。

タイムアウトを5000ミリ秒に設定してから、 java.net.SocketTimeoutException

コードは次のようになります。


try {
   HttpURLConnection.setFollowRedirects(false);
   HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
   con.setRequestMethod("HEAD");

   con.setConnectTimeout(5000); //set timeout to 5 seconds

   return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
} catch (java.net.SocketTimeoutException e) {
   return false;
} catch (java.io.IOException e) {
   return false;
}



3
値を10分に設定しました。しかしそれは私を投げるjava.net.ConnectException: Connection timed out: connect前に2分もアップします。問題の原因を知っていますか?
ペーチェリエ

5
SocketTimeoutExceptionはIOExceptionのサブクラスです。両方のcatchブロックが同じことを行う場合は、IOExceptionをキャッチするだけです。
spaaarky21 2013

2
@ spaaarky21は正しいです。ただし、UIを構築していて、タイムアウトが発生したことをユーザーに通知する場合は、IOExceptionの前にSocketTimeoutExceptionをキャッチする必要があります。キャッチしないと、到達できません。
クロッカー

3
NB !!! setConnectTimeout暗黙的に接続するメソッド(基本的に、すでに接続されている場合にIllegalStateExceptionをスローするすべてのメソッド)の前に呼び出す必要があります。理想的には、setConnectTimeout(readTimeout)を最初に呼び出すメソッドにします。
アダム・ゲント

4
うまくいきませんでした。しかし、を追加した後con.setReadTimeout()、期待どおりに機能しました。
2017

115

このようにタイムアウトを設定できます

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);

2
指定できるタイムアウトの最大値はいくつですか?
ペーチェリエ

7
@Pacerierドキュメントはこれを明示的に述べていません。値が負の場合、IllegalArgumentExceptionをスローします(値0は無期限に待機することを意味します)。タイムアウトは符号なしの32ビット整数であるため、最大タイムアウトは約49日になると思います(このような値が誰にとっても役立つと私は真剣に疑っていますが)。
Jay Sidri

1

HTTP接続がタイムアウトしない場合は、バックグラウンドスレッド自体(AsyncTask、Serviceなど)にタイムアウトチェッカーを実装できます。次のクラスは、特定の期間の後にタイムアウトするCustomize AsyncTaskの例です。

public abstract class AsyncTaskWithTimer<Params, Progress, Result> extends
    AsyncTask<Params, Progress, Result> {

private static final int HTTP_REQUEST_TIMEOUT = 30000;

@Override
protected Result doInBackground(Params... params) {
    createTimeoutListener();
    return doInBackgroundImpl(params);
}

private void createTimeoutListener() {
    Thread timeout = new Thread() {
        public void run() {
            Looper.prepare();

            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    if (AsyncTaskWithTimer.this != null
                            && AsyncTaskWithTimer.this.getStatus() != Status.FINISHED)
                        AsyncTaskWithTimer.this.cancel(true);
                    handler.removeCallbacks(this);
                    Looper.myLooper().quit();
                }
            }, HTTP_REQUEST_TIMEOUT);

            Looper.loop();
        }
    };
    timeout.start();
}

abstract protected Result doInBackgroundImpl(Params... params);
}

このサンプル

public class AsyncTaskWithTimerSample extends AsyncTaskWithTimer<Void, Void, Void> {

    @Override
    protected void onCancelled(Void void) {
        Log.d(TAG, "Async Task onCancelled With Result");
        super.onCancelled(result);
    }

    @Override
    protected void onCancelled() {
        Log.d(TAG, "Async Task onCancelled");
        super.onCancelled();
    }

    @Override
    protected Void doInBackgroundImpl(Void... params) {
        // Do background work
        return null;
    };
 }

cancel()の呼び出しをスケジュールするためだけに新しいルーパースレッドを作成する必要はまったくありません。これはのメインスレッドから実行できますonPreExecute()。また、タスクを手動でキャンセルする場合は、リークを回避するために、スケジュールされた呼び出しもキャンセルする必要があります。
BladeCoder 2015

ここでのポイントは、onPreExecute()ではなく実行時に時間がかかりすぎる場合にdoInBackground()の途中でAsyncTaskをキャンセルすることです。また、時間がかかりすぎて他のインスタンスを保持するAsyncTaskのこのインスタンスのみをキャンセルしたいので、感謝します。あなたのフィードバック。
Ayman Mahgoub 2015

2
私のメッセージは十分に明確ではなかったと思います。onPreExecute()でキャンセルする必要があるとは言いませんでした。onPreExecute()でハンドラーを作成し、メインスレッドから遅延キャンセルをポストする必要があると言いました。この方法では、メインスレッドをルーパースレッドとして使用し、メインスレッドもバックグラウンドスレッドと同時に実行されるため、doInBackground()の実行中に、後でAsyncTaskをキャンセルできます。
BladeCoder 2015

-1

単純な行を追加することで、このような同様の問題の解決策を得ることができました

HttpURLConnection hConn = (HttpURLConnection) url.openConnection();
hConn.setRequestMethod("HEAD");

私の要件は、応答コードを知ることでした。そのためには、完全な応答本文を取得するのではなく、メタ情報を取得するだけで十分でした。

デフォルトのリクエストメソッドはGETであり、返されるまでに時間がかかり、最終的にSocketTimeoutExceptionがスローされました。Request MethodをHEADに設定すると、応答がかなり速くなりました。


1
これは決して解決策ではありません。要求メソッドを、HEAD応答本文を生成しない要求に変更します。
Sveinung Kval Bakken

これは元の質問に何も追加しません。OPの.setRequestMethod("HEAD")コードにあります。奇妙なことに、この説明は、「開いているファイルが多すぎる」という問題を減らすために必要なものでした。ほんとありがと?
Joshua Pinter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.