如何在Java中为Android设置HttpResponse超时时间

337

我创建了以下函数以检查连接状态:

private void checkConnectionStatus() {
    HttpClient httpClient = new DefaultHttpClient();

    try {
      String url = "http://xxx.xxx.xxx.xxx:8000/GaitLink/"
                   + strSessionString + "/ConnectionStatus";
      Log.d("phobos", "performing get " + url);
      HttpGet method = new HttpGet(new URI(url));
      HttpResponse response = httpClient.execute(method);

      if (response != null) {
        String result = getResponse(response.getEntity());
        ...

当我关闭服务器以进行测试时,执行在该行等待了很长时间

HttpResponse response = httpClient.execute(method);

有人知道如何设置超时时间以避免等待太久吗?

谢谢!


这个API没有提供设置DNS查找超时的方法,这将在后台使用。 - undefined
10个回答

625

在我的例子中,设置了两个超时时间。连接超时会抛出 java.net.SocketTimeoutException: Socket is not connected 异常,而套接字超时会抛出 java.net.SocketTimeoutException: The operation timed out 异常。

HttpGet httpGet = new HttpGet(url);
HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established.
// The default value is zero, that means the timeout is not used. 
int timeoutConnection = 3000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT) 
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 5000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
HttpResponse response = httpClient.execute(httpGet);

如果你想设置已存在的HTTP客户端(例如DefaultHttpClient或AndroidHttpClient)的参数,可以使用setParams()函数。

httpClient.setParams(httpParameters);

3
如果连接超时,HttpResponse会返回什么?目前,在我的HTTP请求被发出后,我会检查调用返回时的状态码,但是如果调用超时,当我检查这个代码时,我会得到一个NullPointerException...基本上,当调用超时时我该如何处理这种情况?(我正在使用与您给出的答案非常相似的代码) - Tim
10
尽管文档中写着AndroidHttpClient扩展了DefaultHttpClient,但实际上它只是实现了HttpClient接口。如果你需要使用setParams(HttpParams)方法,你需要使用DefaultHttpClient。 - Ted Hopp
3
嘿,大家好,感谢你们提供的出色答案。但是,我想为连接超时的用户举杯祝酒……有什么办法可以检测到连接超时吗? - Arnab Chakraborty
2
不起作用。我在我的Sony和Moto上测试了,它们都卡住了。 - thecr0w
这种情况无法处理“设备连接到wifi但wifi未连接到互联网”的问题...默认的HTTP客户端超时时间为40秒,AndroidHTTPClient的超时时间为20秒,我们无法将其降低到所需的时间。 - Usman Kurd
显示剩余9条评论

13

在客户端上设置设置:

AndroidHttpClient client = AndroidHttpClient.newInstance("Awesome User Agent V/1.0");
HttpConnectionParams.setConnectionTimeout(client.getParams(), 3000);
HttpConnectionParams.setSoTimeout(client.getParams(), 5000);

我已经在JellyBean上成功使用了这个,但也应该适用于旧平台....

希望有所帮助


HttpClient 有什么关系? - Sazzad Hissain Khan

8
如果您正在使用Jakarta的http客户端库,那么您可以这样做:
        HttpClient client = new HttpClient();
        client.getParams().setParameter(HttpClientParams.CONNECTION_MANAGER_TIMEOUT, new Long(5000));
        client.getParams().setParameter(HttpClientParams.SO_TIMEOUT, new Integer(5000));
        GetMethod method = new GetMethod("http://www.yoururl.com");
        method.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, new Integer(5000));
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
        int statuscode = client.executeMethod(method);

5
HttpClientParams.CONNECTION_MANAGER_TIMEOUT是未知的。 - Tawani
你应该使用 client.getParams().setIntParameter(..) 来设置 *_TIMEOUT 参数。 - loafoe
如何查找?设备已连接到 WiFi,但实际上没有通过 WiFi 传输数据。 - Ganesh Katikar

7

5

对于那些认为@kuester2000的答案无效的人,请注意HTTP请求首先尝试通过DNS请求查找主机IP地址,然后才向服务器发出实际的HTTP请求,因此您可能还需要为DNS请求设置超时时间。

如果您的代码没有为DNS请求设置超时时间而能够正常工作,则是因为您能够连接到DNS服务器或者您正在访问Android DNS缓存。顺便说一句,您可以通过重启设备来清除此缓存。

此代码扩展了原始答案,包括手动DNS查找和自定义超时时间:

//Our objective
String sURL = "http://www.google.com/";
int DNSTimeout = 1000;
int HTTPTimeout = 2000;

//Get the IP of the Host
URL url= null;
try {
     url = ResolveHostIP(sURL,DNSTimeout);
} catch (MalformedURLException e) {
    Log.d("INFO",e.getMessage());
}

if(url==null){
    //the DNS lookup timed out or failed.
}

//Build the request parameters
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, HTTPTimeout);
HttpConnectionParams.setSoTimeout(params, HTTPTimeout);

DefaultHttpClient client = new DefaultHttpClient(params);

HttpResponse httpResponse;
String text;
try {
    //Execute the request (here it blocks the execution until finished or a timeout)
    httpResponse = client.execute(new HttpGet(url.toString()));
} catch (IOException e) {
    //If you hit this probably the connection timed out
    Log.d("INFO",e.getMessage());
}

//If you get here everything went OK so check response code, body or whatever

使用的方法:

//Run the DNS lookup manually to be able to time it out.
public static URL ResolveHostIP (String sURL, int timeout) throws MalformedURLException {
    URL url= new URL(sURL);
    //Resolve the host IP on a new thread
    DNSResolver dnsRes = new DNSResolver(url.getHost());
    Thread t = new Thread(dnsRes);
    t.start();
    //Join the thread for some time
    try {
        t.join(timeout);
    } catch (InterruptedException e) {
        Log.d("DEBUG", "DNS lookup interrupted");
        return null;
    }

    //get the IP of the host
    InetAddress inetAddr = dnsRes.get();
    if(inetAddr==null) {
        Log.d("DEBUG", "DNS timed out.");
        return null;
    }

    //rebuild the URL with the IP and return it
    Log.d("DEBUG", "DNS solved.");
    return new URL(url.getProtocol(),inetAddr.getHostAddress(),url.getPort(),url.getFile());
}   

这个类来自于这篇博客文章。如果你要使用它,请查看备注。

public static class DNSResolver implements Runnable {
    private String domain;
    private InetAddress inetAddr;

    public DNSResolver(String domain) {
        this.domain = domain;
    }

    public void run() {
        try {
            InetAddress addr = InetAddress.getByName(domain);
            set(addr);
        } catch (UnknownHostException e) {
        }
    }

    public synchronized void set(InetAddress inetAddr) {
        this.inetAddr = inetAddr;
    }
    public synchronized InetAddress get() {
        return inetAddr;
    }
}

3

一种选择是使用Square的OkHttp客户端。

添加库依赖项

在build.gradle中,包含以下行:

compile 'com.squareup.okhttp:okhttp:x.x.x'

其中 x.x.x 是所需的库版本。

设置客户端

例如,如果您想设置60秒的超时时间,请按照以下方式进行:

final OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(60, TimeUnit.SECONDS);

注:如果您的minSdkVersion大于8,则可以使用TimeUnit.MINUTES。因此,您可以简单地使用:

okHttpClient.setReadTimeout(1, TimeUnit.MINUTES);
okHttpClient.setConnectTimeout(1, TimeUnit.MINUTES);

有关单位的更多详细信息,请参见TimeUnit


1
在当前版本的OkHttp中,超时需要以不同的方式设置:https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/ConfigureTimeouts.java - thijsonline

1

您可以使用 Httpclient-android-4.3.5 创建 HttpClient 实例,它可以很好地工作。

 SSLContext sslContext = SSLContexts.createSystemDefault();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslContext,
                SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
                RequestConfig.Builder requestConfigBuilder = RequestConfig.custom().setCircularRedirectsAllowed(false).setConnectionRequestTimeout(30*1000).setConnectTimeout(30 * 1000).setMaxRedirects(10).setSocketTimeout(60 * 1000);
        CloseableHttpClient hc = HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(requestConfigBuilder.build()).build();

1
HttpParams httpParameters = new BasicHttpParams();
            HttpProtocolParams.setVersion(httpParameters, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(httpParameters,
                    HTTP.DEFAULT_CONTENT_CHARSET);
            HttpProtocolParams.setUseExpectContinue(httpParameters, true);

            // Set the timeout in milliseconds until a connection is
            // established.
            // The default value is zero, that means the timeout is not used.
            int timeoutConnection = 35 * 1000;
            HttpConnectionParams.setConnectionTimeout(httpParameters,
                    timeoutConnection);
            // Set the default socket timeout (SO_TIMEOUT)
            // in milliseconds which is the timeout for waiting for data.
            int timeoutSocket = 30 * 1000;
            HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

不完整。它与HttpClient有什么关系? - Sazzad Hissain Khan

1
如果您正在使用HttpURLConnection,请按照此处所述调用setConnectTimeout()函数。
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(CONNECT_TIMEOUT);

描述更像是建立连接的超时,而不是HTTP请求? - ctk2021

0
public boolean isInternetWorking(){
    try {
        int timeOut = 5000;
        Socket socket = new Socket();
        SocketAddress socketAddress = new InetSocketAddress("8.8.8.8",53);
        socket.connect(socketAddress,timeOut);
        socket.close();
        return true;
    } catch (IOException e) {
        //silent
    }
    return false;
}

它代表哪个服务器?"8.8.8.8",53 - Junaed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接