Android 4.0 ICS превращает запросы HttpURLConnection GET в запросы POST - PullRequest
11 голосов
/ 18 ноября 2011

Моя Galaxy Nexus прибыла сегодня, и я первым делом загрузил в нее свое приложение, чтобы я мог продемонстрировать его своим друзьям. Часть его функций включает в себя импорт RSS-каналов из Google Reader. Однако, попробовав это, я получил ошибки 405 Method Not Allowed.

Эта проблема специфична для Ice Cream Sandwich. Код, который я прикрепил, прекрасно работает на 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;
    }
}

Есть ли что-нибудь, что может вызвать эту проблему? Может ли эта функция быть лучше закодирована, чтобы избежать этой проблемы?

Большое спасибо заранее.

Ответы [ 5 ]

20 голосов
/ 16 декабря 2011

Это поведение описано в Разработчики Android: HttpURLConnection

HttpURLConnection по умолчанию использует метод GET.Он будет использовать POST, если был вызван setDoOutput (true).

Что странно, так это то, что до 4.0, на самом деле, такого не было, поэтому я думаю, что это сломает многие существующие опубликованные приложения.

Более подробно об этом можно узнать на Android 4.0 превращает GET в POST .

10 голосов
/ 01 декабря 2011

Удаление этой строки сработало для меня:

connection.setDoOutput(true);

4.0 считает, что с этой строкой определенно должно быть POST.

8 голосов
/ 18 ноября 2011

Избавьтесь от этого:

connection.setRequestProperty("Content-Type","application/x-www-form-urlendcoded");

Это говорит API, что это POST.

ОБНОВЛЕНИЕ о том, как это можно сделать с помощью 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();
    }
}
3 голосов
/ 28 августа 2012

Это тот, который получил меня - в основном, установив 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

2 голосов
/ 10 января 2012

Я обнаружил, что до ICS можно было бы сделать POST без тела без предоставления значения Content-Length, однако после ICS вы должны установить Content-Length: 0.

...