HttpURLConnection.getResponseCode()冻结执行/不超时 [英] HttpURLConnection.getResponseCode() freezes execution/doesn't time out

查看:340
本文介绍了HttpURLConnection.getResponseCode()冻结执行/不超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个Android应用程序,该应用程序连接到受密码保护的cPanel服务器(Apache 2.2.22)页面.身份验证凭据正确时,连接没有问题.但是,当凭据不正确时,我的Android应用程序似乎在HttpURLConnection.getResponseCode()方法中冻结.服务器上的日志显示了从我的Android设备发送的数百个请求,所有请求均按预期返回401,但是由于某些原因,这未反映在我的应用程序中.

I'm writing an Android app that connects to a cPanel server (Apache 2.2.22) page which is password protected. When the authentication credentials are correct, I have no problem connecting. However, when the credentials are incorrect, my Android application seems to freeze in the HttpURLConnection.getResponseCode() method. The logs on the server show hundreds of requests being sent from my Android device, all returning a 401 as expected, but for some reason this is not reflected in my application.

这是我的代码,从AsyncTask中执行:

Here is my code, executed from within an AsyncTask:

    @Override
    protected Integer doInBackground(String... bookInfoString) {
        // Stop if cancelled
        if(isCancelled()){
            return null;
        }
        Log.i(getClass().getName(), "SendToDatabase.doInBackground()");

        String apiUrlString = getResources().getString(R.string.url_vages_library);
        try{
            NetworkConnection connection = new NetworkConnection(apiUrlString);
            connection.appendPostData(bookInfoString[0]);
            int responseCode = connection.getResponseCode();
            Log.d(getClass().getName(), "responseCode: " + responseCode);
            return responseCode;
        } catch(IOException e) {
            return null;
        }

    }

这段代码利用了我自己的类NetworkConnection,它只是围绕HttpURLConnection的基本包装类,以避免重复代码.在这里:

This code makes use of my own class NetworkConnection, which is just a basic wrapper class around an HttpURLConnection, to avoid repeating code. Here it is:

public class NetworkConnection {

    private String url;
    private HttpURLConnection connection;

    public NetworkConnection(String urlString) throws IOException{
        Log.i(getClass().getName(), "Building NetworkConnection for the URL \"" + urlString + "\"");

        url = urlString;
        // Build Connection.
        try{
            URL url = new URL(urlString);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setReadTimeout(1000 /* 1 seconds */);
            connection.setConnectTimeout(1000 /* 1 seconds */);
        } catch (MalformedURLException e) {
            // Impossible: The only two URLs used in the app are taken from string resources.
            e.printStackTrace();
        } catch (ProtocolException e) {
            // Impossible: "GET" is a perfectly valid request method.
            e.printStackTrace();
        }
    }

    public void appendPostData(String postData) {

        try{
            Log.d(getClass().getName(), "appendPostData() called.\n" + postData);

            Log.d(getClass().getName(), "connection.getConnectTimeout(): " + connection.getConnectTimeout());
            Log.d(getClass().getName(), "connection.getReadTimeout(): " + connection.getReadTimeout());

            // Modify connection settings.
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "application/json");

            // Get OutputStream and attach POST data.
            OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
            writer.write(postData);
            if(writer != null){
                writer.flush();
                writer.close();
            }

        } catch (SocketTimeoutException e) {
            Log.w(getClass().getName(), "Connection timed out.");
        } catch (ProtocolException e) {
            // Impossible: "POST" is a perfectly valid request method.
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // Impossible: "UTF-8" is a perfectly valid encoding.
            e.printStackTrace();
        } catch (IOException e) {
            // Pretty sure this is impossible but not 100%.
            e.printStackTrace();
        }
    }

    public int getResponseCode() throws IOException{
        Log.i(getClass().getName(), "getResponseCode()");
        int responseCode = connection.getResponseCode();
        Log.i(getClass().getName(), "responseCode: " + responseCode);
        return responseCode;
    }

    public void disconnect(){
        Log.i(getClass().getName(), "disconnect()");
        connection.disconnect();
    }
}

最后,这是logcat日志的一小部分:

And finally, here is a fraction of the logcat logs:

05-03 11:01:16.315: D/vages.library.NetworkConnection(3408): connection.getConnectTimeout(): 1000
05-03 11:01:16.315: D/vages.library.NetworkConnection(3408): connection.getReadTimeout(): 1000
05-03 11:01:16.585: I/vages.library.NetworkConnection(3408): getResponseCode()
05-03 11:04:06.395: I/vages.library.MainActivity$SendToDatabase(3408): SendToDatabase.onPostExecute(null)

您可以看到该方法似乎在随机的时间后仅返回null.我等待的最长时间恰好是15分钟.在最后两个信息日志之间,还有来自dalikvm的多个内存日志(GC_CONCURRENT),我已省略了它们.

You can see the the method seems to just return null after a random amount of time. The longest I have waited was exactly 15 minutes. There are also several memory logs (GC_CONCURRENT) from dalikvm between the last two info logs which I have omitted.

我还应该说,虽然我不认为这会引起任何问题,但目前我并未使用https.对于此问题的任何反馈,我将不胜感激,无论是完整的答案还是仅是告诉我什么不是问题的评论,因为我仍然不确定该问题是服务器端还是客户端-侧.

I should also say that at the moment I am not using https, although I do not believe that should cause any problems. I would be very grateful for any feedback with this, whether it's a complete answer or just a comment telling me what isn't the problem, as I am still unsure whether this problem is server-side or client-side.

非常感谢你, 威廉

编辑:我之前忘记提及,我将身份验证凭据附加到自己的自定义java.net.Authenticator:

I forgot to mention before, I am attaching my authentication credentials with my own custom java.net.Authenticator:

public class CustomAuthenticator extends Authenticator {

    Context mContext;

    public CustomAuthenticator(Context context){
        super();
        mContext = context;
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        String username = sharedPreferences.getString(SettingsActivity.KEY_USERNAME_PREFERENCE, null);
        String password = sharedPreferences.getString(SettingsActivity.KEY_PASSWORD_PREFERENCE, null);

        return new PasswordAuthentication(username, password.toCharArray());
    }
}

我在活动的onCreate()方法中设置的

:

which I set in the activity'sonCreate() method:

Authenticator.setDefault(new CustomAuthenticator(mContext));

此外,我已经使用curl来请求受密码保护的资源,并且按预期收到了401.我现在假设问题出在客户端.

Also, I have used curl to request the password protected resource, and have received a 401 as expected. I am now assuming the problem is client-side.

推荐答案

似乎是问题.它已经很老了,所以我不知道它是否仍然存在.

It seems to be an issue with using Authenticator in POST connections. It's quite old so I don't know if it still exists.

我会尝试两件事:

  • AuthenticatorgetPasswordAuthentication中添加一条日志行,以查看是否被有效调用.如果未打印任何内容,则应检查是否在调用默认值Authenticator之前添加了默认值.您说您是在onCreate()中进行的,因此应该没问题,但是可以肯定的是很好.
  • 避免使用身份验证器(至少出于测试目的),并直接在HTTP请求中发送身份验证信息.我通常这样做:

  • Add a log line in the getPasswordAuthentication of the Authenticator to see if it's effectively called. If nothing is printed, you should check that you add the default Authenticator before it's called. You say you do it in the onCreate(), so it should be fine but it's good to be sure.
  • Avoid using the Authenticator (at least for testing purposes) and send the auth info directly in the HTTP Request. I usually do it this way:

String auth = user + ":" + pass;
conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization", 
               "Basic " + Base64.encode(auth.getBytes()));
// Set other parameters and read the result...

这篇关于HttpURLConnection.getResponseCode()冻结执行/不超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆