Android 4.0 ICS将HttpURLConnection的GET请求转换为POST请求

11

我的Galaxy Nexus今天到了,我做的第一件事之一就是加载我的应用程序,这样我就可以向朋友们展示它。它的部分功能涉及从Google Reader导入RSS订阅。但是,在尝试时,我收到了405方法不允许错误。

这个问题只出现在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

该行为在Android Developers: HttpURLConnection中有所描述。

HttpURLConnection默认使用GET方法。如果调用了setDoOutput(true),它会使用POST方法。

然而奇怪的是,这实际上直到4.0版本才成为了默认行为,因此我想它可能会破坏许多现有的发布应用程序。

关于此问题,您可以参考Android 4.0将GET转换为POST


10

移除这行代码对我有用:

connection.setDoOutput(true);

根据这行代码,4.0版本认为应该使用POST方法。


2
谢谢Fedor,这对我也有用。我遇到了与GET方法相同的问题。当我使用setDoOutPut(true)调用GET方法时,返回了Http 405:方法不允许的消息。再次感谢。 - PrashantAdesara

8

摆脱这个:

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();
    }
}

不行。删除那一行完全没有任何影响。 - Michael Dodd
1
好的,那么你也可以尝试使用HttpClient。 - Vit Khudenko
@Michael Dodd:请查看更新部分。 - Vit Khudenko
我有完全相同的问题,我没有设置“Content-Type”属性,但它仍然无法工作... - Zennichimaro
编辑:不用担心,@djh的答案已经解决了这个问题(如果调用了setDoOutput(true),它将使用POST)。 - Zennichimaro

3
这是一个让我困惑的问题 - 通过设置setDoOutput(true),它会在连接时强制执行POST请求,即使你在setRequestMethod中指定了GET方法:
HttpURLConnection默认使用GET方法。如果调用了setDoOutput(true),它将使用POST方法。其他HTTP方法(OPTIONS、HEAD、PUT、DELETE和TRACE)可以与setRequestMethod(String)一起使用。
这在一段时间前曾经困扰过我,非常令人沮丧...
请参见http://developer.android.com/reference/java/net/HttpURLConnection.html,并转到HTTP Methods标题。

2

我发现在ICS之前,可以不提供Content-Length值而进行无主体POST请求,但在ICS之后,必须设置Content-Length: 0。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接