Android 4.0 ICS turning HttpURLConnection GET requ

2020-01-29 08:09发布

My Galaxy Nexus arrived today, and one of the first things I did was to load my app onto it so I could demonstrate it to my friends. Part of its functionality involves importing RSS Feeds from Google Reader. However, upon trying this, I was getting 405 Method Not Allowed errors.

This problem is Ice Cream Sandwich-specific. The code I've attached works fine on Gingerbread and Honeycomb. I've traced the error down to the moment the connection is made, when the GET request magically turns into a POST request.

/**
 * 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;
    }
}

Is there anything that could be causing this problem? Could this function be better coded to avoid this problem?

Many thanks in advance.

5条回答
在下西门庆
2楼-- · 2020-01-29 08:17

This behaviour is described in Android Developers: HttpURLConnection

HttpURLConnection uses the GET method by default. It will use POST if setDoOutput(true) has been called.

What's strange though is that this has not actually been the behaviour until 4.0, so I would imagine it's going to break many existing published apps.

There is more on this at Android 4.0 turns GET into POST.

查看更多
ら.Afraid
3楼-- · 2020-01-29 08:18

Get rid of this:

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

This tells the API this is a POST.

UPDATE on how it could be done via 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();
    }
}
查看更多
Lonely孤独者°
4楼-- · 2020-01-29 08:27

Removing this line worked for me:

connection.setDoOutput(true);

4.0 thinks with this line it should definitely be POST.

查看更多
家丑人穷心不美
5楼-- · 2020-01-29 08:33

I've found that pre-ICS one could get away with making a body-less POST without providing a Content-Length value, however post-ICS you must set Content-Length: 0.

查看更多
贪生不怕死
6楼-- · 2020-01-29 08:36

This is one that got me - basically by setting setDoOutput(true) it forces a POST request when you make the connection, even if you specify this is a GET in the setRequestMethod:

HttpURLConnection uses the GET method by default. It will use POST if setDoOutput(true) has been called. Other HTTP methods (OPTIONS, HEAD, PUT, DELETE and TRACE) can be used with setRequestMethod(String).

This caught me a while back - very frustrating ...

See http://developer.android.com/reference/java/net/HttpURLConnection.html and go to HTTP Methods heading

查看更多
登录 后发表回答