Configurações de tempo limite da conexão HttpURLC

123

Desejo retornar false se a URL demorar mais de 5 segundos para conectar - como isso é possível usando Java? Aqui está o código que estou usando para verificar se o URL é válido

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

Respostas:

201

HttpURLConnectionpossui um método setConnectTimeout .

Basta definir o tempo limite para 5000 milissegundos e depois capturar java.net.SocketTimeoutException

Seu código deve ser algo como isto:


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
fonte
3
Defino o valor para 10 minutos. No entanto, ele me joga um java.net.ConnectException: Connection timed out: connectantes mesmo de 2 minutos acabar. Você sabe o que está causando o problema?
Pacerier
5
SocketTimeoutException é uma subclasse de IOException. Se os dois blocos catch fizerem a mesma coisa, você poderá capturar IOException.
spaaarky21
2
@ spaaarky21 está correto. Se, no entanto, você estiver criando uma interface do usuário e desejar notificar seus usuários que ocorreu um tempo limite, você deverá capturar SocketTimeoutException antes de IOException, caso contrário, será inacessível.
Clocker
3
NB !!! você precisa chamar setConnectTimeoutantes de qualquer um dos métodos que se conectam implicitamente (basicamente todos os métodos que lançam IllegalStateException, se já estiver conectado). Idealmente, faça do setConnectTimeout (readTimeout) os primeiros métodos chamados.
Adam Gent
4
Não funcionou para mim. Mas, depois de adicionar con.setReadTimeout(), funcionou como esperado.
Paulo
115

Você pode definir um tempo limite como este,

con.setConnectTimeout(connectTimeout);
con.setReadTimeout(socketTimeout);
ZZ Coder
fonte
2
Qual é o valor máximo do tempo limite que podemos especificar?
Pacerier
7
@Pacerier Os documentos não afirmam isso explicitamente. Ele lança uma IllegalArgumentException se o valor for negativo (um valor 0 significaria esperar indefinidamente). Como o tempo limite é um int de 32 bits sem sinal, eu acho que o tempo limite máximo seria de 49 dias (embora eu duvide muito que esse valor seja útil para qualquer pessoa).
Jay Sidri
1

Se a conexão HTTP não atingir o tempo limite, você poderá implementar o verificador de tempo limite no próprio encadeamento em segundo plano (AsyncTask, Service, etc), a seguinte classe é um exemplo para Personalizar o AsyncTask, que excede o tempo limite após determinado período

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);
}

Uma amostra para isso

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;
    };
 }
Ayman Mahgoub
fonte
É absolutamente desnecessário criar um novo thread de looper apenas para agendar uma chamada para cancelar (). Você pode fazer isso a partir do thread principal onPreExecute(). Além disso, se você cancelar a tarefa manualmente, também deverá cancelar a chamada agendada para evitar vazamentos.
BladeCoder
O ponto aqui é cancelar o AsyncTask no meio do doInBackground () quando leva muito tempo na execução, não no onPreExecute (), também quero cancelar apenas esta instância do AsyncTask que leva muito tempo e mantém as outras, muito apreciadas seu retorno.
Ayman Mahgoub
2
Acho que minha mensagem não foi clara o suficiente. Eu não disse que você deveria cancelar em onPreExecute (), eu disse que você deveria criar o Handler em onPreExecute () e postar o cancelamento atrasado no thread principal. Dessa forma, você usará o segmento principal como segmento looper e, claro, poderá cancelar o AsyncTask mais tarde, enquanto doInBackground () estiver em execução, porque o segmento principal também é executado simultaneamente com o segmento de segundo plano.
precisa saber é o seguinte
-1

Eu poderia obter solução para um problema semelhante com a adição de uma linha simples

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

Meu requisito era conhecer o código de resposta e, para isso, basta obter as metainformações, em vez de obter o corpo de resposta completo.

O método de solicitação padrão é GET e demorava muito tempo para retornar, finalmente me lançando SocketTimeoutException. A resposta foi bem rápida quando defino o método de solicitação como HEAD.

Subrata Nath
fonte
1
Essa não é a solução, você está alterando o método de solicitação para uma HEADsolicitação que não produzirá nenhum corpo de resposta.
Sveinung Kval Bakken
Isso não adiciona nada à pergunta original. OP tem .setRequestMethod("HEAD")em seu código. Estranhamente, essa descrição era exatamente o que eu precisava para reduzir meu problema de "Muitos arquivos abertos". Então obrigado?
Joshua Pinter