Android 4.0 ICS превращает HttpURLConnection GET запросы в запросы POST
Моя Galaxy Nexus прибыла сегодня, и одна из первых вещей, которую я сделал, это загрузить мое приложение, чтобы я мог продемонстрировать это своим друзьям. Часть его функций включает импорт RSS-каналов из Google Reader. Однако, при попытке этого, я получал 405 ошибок, не допускаемых методом.
Эта проблема связана с сандвичем с мороженым. Код, который я добавил, отлично работает на Gingerbread и Honeycomb. Я проследил ошибку до момента соединения, когда запрос GET волшебным образом превращается в запрос POST.
/**
* Get the authentication token from Google
* @param auth The Auth Key generated in getAuth()
* @return The authentication token
*/
private String getToken(String auth) {
final String tokenAddress = "https://www.google.com/reader/api/0/token";
String response = "";
URL tokenUrl;
try {
tokenUrl = new URL(tokenAddress);
HttpURLConnection connection = (HttpURLConnection) tokenUrl.openConnection();
connection.setRequestMethod("GET");
connection.addRequestProperty("Authorization", "GoogleLogin auth=" + auth);
connection.setRequestProperty("Content-Type","application/x-www-form-urlendcoded");
connection.setUseCaches(false);
connection.setDoOutput(true);
Log.d(TAG, "Initial method: " + connection.getRequestMethod()); // Still GET at this point
try {
connection.connect();
Log.d(TAG, "Connected. Method is: " + connection.getRequestMethod()); // Has now turned into POST, causing the 405 error
InputStream in = new BufferedInputStream(connection.getInputStream());
response = convertStreamToString(in);
connection.disconnect();
return response;
}
catch (Exception e) {
Log.d(TAG, "Something bad happened, response code was " + connection.getResponseCode()); // Error 405
Log.d(TAG, "Method was " + connection.getRequestMethod()); // POST again
Log.d(TAG, "Auth string was " + auth);
e.printStackTrace();
connection.disconnect();
return null;
}
}
catch(Exception e) {
// Stuff
Log.d(TAG, "Something bad happened.");
e.printStackTrace();
return null;
}
}
Есть ли что-то, что может вызвать эту проблему? Может ли эта функция лучше кодироваться, чтобы избежать этой проблемы?
Большое спасибо заранее.
Ответы
Ответ 1
Это поведение описано в Android Developers: HttpURLConnection
HttpURLConnection использует метод GET по умолчанию. Он будет использовать POST, если вызывается setDoOutput (true).
Что странно, так это то, что на самом деле это не было до 4.0, поэтому я бы предположил, что он сломает многие существующие опубликованные приложения.
Об этом в разделе добавлен Android 4.0, который превращает GET в POST.
Ответ 2
Удаление этой строки работало для меня:
connection.setDoOutput(true);
4.0 думает, что с этой строкой обязательно должен быть POST.
Ответ 3
Избавьтесь от этого:
connection.setRequestProperty("Content-Type","application/x-www-form-urlendcoded");
Это говорит API, что это POST.
UPDATE о том, как это сделать через HttpClient
:
String response = null;
HttpClient httpclient = null;
try {
HttpGet httpget = new HttpGet(yourUrl);
httpget.setHeader("Authorization", "GoogleLogin auth=" + auth);
httpclient = new DefaultHttpClient();
HttpResponse httpResponse = httpclient.execute(httpget);
final int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new Exception("Got HTTP " + statusCode
+ " (" + httpResponse.getStatusLine().getReasonPhrase() + ')');
}
response = EntityUtils.toString(httpResponse.getEntity(), HTTP.UTF_8);
} catch (Exception e) {
e.printStackTrace();
// do some error processing here
} finally {
if (httpclient != null) {
httpclient.getConnectionManager().shutdown();
}
}
Ответ 4
Это то, что меня достало - в основном, установив setDoOutput (true), он заставляет POST-запрос при создании соединения , даже если вы указываете, что это GET в setRequestMethod:
HttpURLConnection использует метод GET по умолчанию. Он будет использовать POST, если вызывается setDoOutput (true). Другие методы HTTP (OPTIONS, HEAD, PUT, DELETE и TRACE) можно использовать с setRequestMethod (String).
Это поймало меня на некоторое время назад - очень расстраивает...
Смотрите http://developer.android.com/reference/java/net/HttpURLConnection.html и перейдите в заголовок Методы HTTP
Ответ 5
Я обнаружил, что pre-ICS может уйти с созданием безпоточного POST без предоставления значения Content-Length, однако после ICS вы должны установить Content-Length: 0.