Настройки тайм-аута HttpURLConnection

123

Я хочу вернуть false, если для подключения URL-адреса требуется более 5 секунд - как это возможно с использованием 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;
}


dbyrne
источник
3
Я установил значение 10 минут. Однако это бросает меня еще java.net.ConnectException: Connection timed out: connectдо того, как истекло 2 минуты. Вы знаете, что вызывает проблему?
Pacerier
5
SocketTimeoutException - это подкласс IOException. Если оба блока catch делают одно и то же, вы можете просто поймать IOException.
spaaarky21 05
2
@ spaaarky21 правильный. Если, однако, вы создаете пользовательский интерфейс и хотите уведомить своих пользователей о том, что истекло время ожидания, вы должны перехватить SocketTimeoutException до IOException, в противном случае оно будет недоступно.
Clocker
3
NB !!! вам нужно вызвать setConnectTimeoutперед любым из методов, которые неявно подключаются (в основном все методы, которые вызывают IllegalStateException, если они уже подключены). В идеале первым вызываемым методом сделайте setConnectTimeout (readTimeout).
Адам Гент
4
У меня это не сработало. Но после добавления con.setReadTimeout()все заработало как положено.
Пауло
115

Вы можете установить тайм-аут следующим образом:

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);
ZZ Coder
источник
2
Какое максимальное значение тайм-аута мы можем указать?
Pacerier
7
@Pacerier В документации это явно не указано. Он вызывает исключение IllegalArgumentException, если значение отрицательное (значение 0 означало бы ожидание бесконечно). Поскольку тайм-аут представляет собой 32-битное целое число без знака, я предполагаю, что максимальный тайм-аут будет около 49 дней (хотя я серьезно сомневаюсь, что такое значение будет полезно для кого-либо).
Джей Сидри,
1

Если HTTP-соединение не истекает, вы можете реализовать проверку времени ожидания в самом фоновом потоке (AsyncTask, Service и т. Д.), Следующий класс является примером для настройки 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
Дело здесь в том, чтобы отменить AsyncTask в середине doInBackground (), когда выполнение занимает слишком много времени, а не в onPreExecute (), также я хочу отменить только этот экземпляр AsyncTask, который занимает слишком много времени, и оставить остальных, очень признателен ваш отзыв.
Ayman Mahgoub
2
Я думаю, что мое сообщение было недостаточно ясным. Я не говорил, что вам следует отменить в onPreExecute (), я сказал, что вы должны создать обработчик в onPreExecute () и опубликовать отложенную отмену из основного потока. Таким образом, вы будете использовать основной поток в качестве потока петлителя, и вы, конечно, можете отменить AsyncTask позже, пока выполняется doInBackground (), потому что основной поток также выполняется одновременно с фоновым потоком.
BladeCoder
-1

Я мог бы получить решение такой похожей проблемы, добавив простую строку

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

Мое требование состояло в том, чтобы знать код ответа, и для этого было достаточно просто получить метаинформацию, вместо получения полного тела ответа.

Метод запроса по умолчанию - GET, и для его возврата потребовалось много времени, и я, наконец, выбросил SocketTimeoutException. Ответ был довольно быстрым, когда я установил для метода запроса значение HEAD.

Субрата Натх
источник
1
Это никоим образом не является решением, вы меняете метод запроса на HEADзапрос, который не приведет к созданию тела ответа.
Sveinung Kval Bakken
Это ничего не добавляет к исходному вопросу. ОП имеет .setRequestMethod("HEAD")в своем коде. Как ни странно, это описание было именно тем, что мне нужно, чтобы уменьшить мою проблему «Слишком много открытых файлов». Так что спасибо?
Джошуа Пинтер