Android忽略DefaultHttpClient超时参数

时间:2014-11-28 09:53:03

标签: android timeout httprequest httpclient

我在Android上遇到了DefaultHttpClient的超时问题。我尝试使用以下代码设置超时:

HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 4000);
HttpConnectionParams.setSoTimeout(httpParameters, 4000);

但是,如果设备连接到没有Internet连接的网络,则永远不会触发超时,并且http请求的执行永远不会引发任何超时异常。我正在执行http请求,如下所示:

HttpResponse httpResponse = client.execute(request);

我还试图在HttpRequest上设置超时,并使用以下行:

HttpRequestBase request = ...
request.setParams(httpParameters);

Android似乎忽略了超时设置,当在没有互联网连接的网络上执行http请求时,所有请求在大约20秒后失败,而不是在我的超时设置之后。

我还尝试关闭所有互联网连接,并在使用并行线程超时后中止http请求。我使用了以下代码:

HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();

HttpRequestBase request = ...
request.setParams(httpParameters);

HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutReal);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutReal);

request.setParams(httpParameters);
((DefaultHttpClient) client).setParams(httpParameters);

Thread t = new Thread(){
    public void run()
    {
        try
        {
            Thread.sleep(4000);
            request.abort();
            client.getConnectionManager().closeExpiredConnections();
            client.getConnectionManager().closeIdleConnections(4000,TimeUnit.MILLISECONDS);
            client.getConnectionManager().shutdown();
            Log.i("TEST SHUTDOWN","SHUT DOWN ALL CONNECTIONS");
                }
            catch (InterruptedException e)
            {
            }
        }
    };

try
{
    t.start();
    HttpResponse httpResponse = client.execute(request);
}
catch (Exception e)
{
    Log.i("TEST SHUTDOWN","EXCEPTION "+e);
}
finally
{
    t.interrupt();
}

但是即使我从日志中看到请求被中止并且连接管理器被关闭,请求的执行也不会被中断/中止,并且在超时设置时不会引发异常。 请求始终在20秒后结束。

知道为什么吗?

4 个答案:

答案 0 :(得分:7)

您可能看到的是DNS查找超时。当您的HTTP客户端尝试建立连接时,它首先要尝试将您的URL的主机名解析为IP地址。执行此操作时,它不会考虑您的超时设置(这些超时值仅在尝试实际建立套接字连接时使用)。如果您没有良好的互联网连接,您的DNS查找将停止,直到超时为止。一旦发生这种情况,您的HTTP请求将立即失败UnknownHostException

不幸的是,您无法控制DNS超时,因此解决问题的唯一方法是首先确定您的DNS解析是否正常。您应该在一个单独的主题中执行此操作,如果您在几秒钟内未获得成功的主机解析,则您知道您的Internet连接不可靠并且您甚至不必尝试HTTP请求。

所以你可以尝试这样的事情:

HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();

HttpRequestBase request = ...
request.setParams(httpParameters);

HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutReal);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutReal);

request.setParams(httpParameters);
((DefaultHttpClient) client).setParams(httpParameters);

// The thread that is waiting to execute the HTTP request
final Thread waitingThread = Thread.currentThread();

Thread t = new Thread() {
    boolean running = true;
    public void run() {
        try {
            // Try to resolve the host name
            InetAddress addr = InetAddress.getByName (hostname);
            // Successful resolution, notify the waiting thread
            if (running) {
                // Signal the waiting thread that it can do the HTTP request now
                waitingThread.interrupt();
            }
        } catch (Exception e) {
            // Some problem, just ignore it
        }
    }
};

try {
    // Start name resolution
    t.start();
    // Sleep for as long as we are willing to wait for the DNS resolution
    Thread.sleep(4000);
    // If we slept the entire time without getting interrupted, the DNS resolution took too long
    //  so assume we have no connectivity.
    t.running = false; // We don't want to be interrupted anymore
    // Don't even bother trying the HTTP request now, we've used up all the time we have
} catch (InterruptedException ie) {
    // We got interrupted, so the DNS resolution must have been successful. Do the HTTP request now
    HttpResponse httpResponse = client.execute(request);
}

我在没有尝试的情况下编写此代码,请原谅任何拼写错误或丢失分号。你应该明白这个想法。

答案 1 :(得分:1)

您可以尝试使用AndroidHttpClient而不是DefaultHttpClient。它有一些针对Android的特定设置。

或者,您可以尝试替换以下行:

HttpParams httpParameters = client.getParams();

使用以下行

HttpParams httpParameters = new BasicHttpParams();

我不知道这是否是正确答案,但希望这有帮助。

答案 2 :(得分:0)

问题的{20}部分rfc2616指定5次重定向时间4000 milis = 20秒。解决方案是在尝试网络访问之前检查网络连接。

// check for network connection
        ConnectivityManager connMgr = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connMgr == null) {
            return false;  // I get a null here when there is no connection on my lg f6.
        }

        // check ok to process
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
        if (networkInfo == null || !networkInfo.isConnected()) {
            return false;
        }

       return true;

答案 3 :(得分:0)

好吧,我遇到了类似的问题。这就是我解决它的方法。

首先,我创建了一个HttpParams的实例:

HttpParams params = new BasicHttpParams();

然后,我没有手动设置设置。相反,我使用HttpConnectionParams类来执行此操作。例如:

HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, httpTimeout * 1000);
HttpConnectionParams.setSoTimeout(params, httpTimeout * 1000);

然后,当我实例化html客户端时,我传递了创建的参数:

HttpClient client = new DefaultHttpClient(params);

我也使用客户端连接管理器,因此,我将其作为上述调用中的第一个参数传递。

因此,诀窍是通过传递已经设置的参数来创建HttpClient,然后不再对它们进行处理。

希望这适合你。

编辑:您是否试图阻止重定向? HttpClientParams.setRedirecting(params, setRedirecting);