我正在編寫一個連接到受密碼保護的cPanel服務器(Apache 2.2.22)頁面的Android應用程序。當身份驗證憑據正確時,我沒有任何問題連接。但是,當憑據不正確時,我的Android應用程序似乎凍結在HttpURLConnection.getResponseCode()
方法中。服務器上的日誌顯示從我的Android設備發送了數百個請求,所有請求都按照預期返回了401,但出於某種原因,這並未反映在我的應用程序中。HttpURLConnection.getResponseCode()凍結執行/不超時
這裏是我的代碼,從內部的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());
}
}
我在活動的設置onCreate()
方法:
Authenticator.setDefault(new CustomAuthenticator(mContext));
另外,我已經使用curl來請求密碼保護資源,並且收到了預期的401。我現在假設問題是客戶端。
對不起,也許我瞎了,但我看不出現在你在哪裏發送您的身份驗證憑據。無論如何,也許你可以使用curl來嘗試請求,看看你會得到什麼樣的輸出:'curl -v「http://yoururl.com」-u user:password'。如果不起作用,問題可能出現在服務器端。 – Esparver 2013-05-03 11:36:22
謝謝@Esparver,我已經在curl中試過了,它按照預期返回了401。所以我想這是客戶端問題。 我使用java.net.Authenticator發送我的身份驗證憑據。我會附上這段代碼給我的答案。 – 2013-05-03 11:54:40