パスワードで保護された 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 の基本的なラッパー クラスである独自の class を使用しています。ここにあります:
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分でした。省略した最後の 2 つの情報ログの間には、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 を受け取りました。私は今、問題がクライアント側にあると仮定しています。