我正在编写一个连接到受密码保护的cPanel服务器(Apache 2.2.22)页面的Android应用程序.当身份验证凭据正确时,我没有连接问题.但是,当凭据不正确时,我的Android应用程序似乎在HttpURLConnection.getResponseCode()方法中冻结.服务器上的日志显示从我的Android设备发送的数百个请求,所有请求都按预期返回401,但由于某种原因,这不会反映在我的应用程序中.
这是我的代码,从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的基本包装类,以避免重复代码.这里是:
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日志的一小部分:
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).
我还应该说,目前我没有使用https,虽然我不认为这会导致任何问题.我将非常感谢任何反馈,无论是完整的答案还是只是评论告诉我什么不是问题,因为我仍然不确定这个问题是服务器端还是客户端.
非常感谢你,
威廉
编辑:我之前忘记提到,我正在使用我自己的自定义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());
}
}
我在activity’sonCreate()方法中设置:
Authenticator.setDefault(new CustomAuthenticator(mContext));
此外,我使用curl请求受密码保护的资源,并按预期收到了401.我现在假设问题是客户端问题.
解决方法:
在POST连接中使用Authenticator似乎是一个issue.它已经很老了所以我不知道它是否仍然存在.
我会尝试两件事:
>在Authenticator的getPasswordAuthentication中添加一个日志行,看看它是否被有效调用.如果没有打印任何内容,则应在检查之前检查是否添加了默认的Authenticator.你说你是在onCreate()中做的,所以它应该没问题,但确定是好的.
>避免使用Authenticator(至少用于测试目的)并直接在HTTP请求中发送身份验证信息.我通常这样做:
String auth = user + ":" + pass;
conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization",
"Basic " + Base64.encode(auth.getBytes()));
// Set other parameters and read the result...