【问题标题】:HttpURLConnection worked fine in Android 2.x but NOT in 4.1: No authentication challenges foundHttpURLConnection 在 Android 2.x 中运行良好,但在 4.1 中运行良好:未发现身份验证挑战
【发布时间】:2012-08-04 17:09:03
【问题描述】:

我有一些典型的代码,它们使用 HttpURLConnection 来获取带有 URL 的文件。 他们在 android 1.x 和 2.x 中运行良好。但在 Android 4.1 中失败了!

我在网上搜索过,但几乎没有找到类似的信息。 有人可以帮忙调查一下这个问题吗?

private String mURLStr; 
private HttpURLConnection mHttpConnection;

...

url = new URL(mURLStr);

...

mHttpConnection = (HttpURLConnection) url.openConnection();
mHttpConnection.setDoOutput(true);
mHttpConnection.setRequestMethod("GET");

...

InputStream is = mHttpConnection.getInputStream();

getInputStream 方法抛出异常:

08-01 15:56:48.856: W/System.err(13613): java.io.IOException: No authentication challenges found
08-01 15:56:48.856: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.getAuthorizationCredentials(HttpURLConnectionImpl.java:427)
08-01 15:56:48.866: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.processAuthHeader(HttpURLConnectionImpl.java:407)
08-01 15:56:48.866: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.processResponseHeaders(HttpURLConnectionImpl.java:356)
08-01 15:56:48.866: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:292)
08-01 15:56:48.866: W/System.err(13613):      at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:168)
...

【问题讨论】:

  • 在我删除'mHttpConnection.setDoOutput(true)'行后它工作了!似乎这个问题与数百万其他问题的原因相同:如果 setDoOutput(true),Android 4.x 会将 http GET 转换为 POST! For your information: http://webdiary.com/tag/java-net-httpurlconnection/
  • 我确实有同样的问题,但我不使用setDoOutput()。在 Android 4.0 Ice Cream Sandwich (ICS) 上一切正常,但在 Android 4.1 Jelly Bean (JB) 上就坏了。顺便说一句,setDoOutput() 将请求转换为 POST 请求是完全有道理的,因为 GET 请求的正文中不应包含有效负载。

标签: android authentication httpurlconnection


【解决方案1】:

我目前面临同样的问题。在 4.1 Jelly Bean 上,我在 HttpURLConnection 上调用 getResponseCode() 时收到 IOException“未找到身份验证挑战”。

我在网上搜索了一下Android源代码有什么变化,发现如下: 4.0.4(工作):https://bitbucket.org/seandroid/libcore/src/7ecbe081ec95/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java 4.1.1(不工作):https://bitbucket.org/seandroid/libcore/src/6b27266a2856/luni/src/main/java/libcore/net/http/HttpURLConnectionImpl.java

正如我们在 4.1 JB 中看到的,getAuthorizationCredentials() 方法会抛出 IOException。如果响应代码为 401 或 407,它会使用 HeaderParser.parseChallenges(..) 解析在响应中找到的质询标头。如果返回的 List 为空,则抛出异常。

https://bitbucket.org/seandroid/libcore/src/6b27266a2856/luni/src/main/java/libcore/net/http/HeaderParser.java

我们目前正在调查究竟是什么导致该 List 为空,但怀疑我们的服务器可能在质询标头中使用 realm=... 而不是 realm="..."。缺少引号可能是导致此问题的原因。我们必须进一步调查是否确实如此,以及我们是否可以让它发挥作用。

【讨论】:

  • +1 以获得清晰的解释和代码链接。代码还期望 realm=" 成为方案之后的第一个参数。
  • 现在我们已经能够验证没有引号的realm=的使用确实是导致我们这个错误的原因。我们能够在后端对此进行更改,现在一切都按预期工作。
  • 我最终通过删除mHttpConnection.setDoOutput(true);使我的应用程序在android 4.x下运行。但我仍然不清楚根本原因。
  • +1 表示出色的响应。我这边的问题是服务器返回 realm=... 而不是 realm="..." 。修复了这个问题,应用开始在 ICS 和 JB 上运行
  • 您找到解决方法了吗?它适用于 kitkat,但不适用于 JB
【解决方案2】:

RFC2617:

401(未经授权)响应消息被源服务器使用 挑战用户代理的授权。此响应必须 包括一个 WWW-Authenticate 头字段,其中至少包含一个 适用于所请求资源的挑战。

在 Android 中,当服务器返回未设置 WWW-Authenticate 标头的 401 Unauthorized407 Proxy Authentication Required 状态代码时,HttpURLConnection getResponseCode() 方法会抛出 java.io.IOException: No authentication challenges found

如果您拥有服务器端 API,则可以通过在返回 401 或 407 时添加所需的 WWW-Authenticate 标头来修复它。在我的例子中,我在 PHP 中修复它如下:

header('WWW-Authenticate: OAuth realm="users"');
header('HTTP/1.1 401 Unauthorized');

【讨论】:

    【解决方案3】:

    我也有同样的问题。我找到了这个解决方法,但它不适用于 Android 2。在 Jelly Bean 上,它运行良好。只需使用 getErrorStream() 而不是 getInputStream()。

    try
    {
        responseStream = new BufferedInputStream(connection.getInputStream());
    }
    catch(IOException e)
    {
        responseStream = new BufferedInputStream(connection.getErrorStream());
    }
    

    【讨论】:

      【解决方案4】:

      标题

      我已经解决了果冻豆的问题。上述场景请使用以下代码

      DefaultHttpClient client = new DefaultHttpClient();
      client.getCredentialsProvider().setCredentials(new AuthScope(null, -1), new UsernamePasswordCredentials(userName,userPass));
      HttpGet request = new HttpGet();
      request.addHeader("Accept", "application/xml");
      request.setURI(new URI(service));
      HttpResponse response = client.execute(request);
      

      您得到了所需的正确响应。

      【讨论】:

        【解决方案5】:

        我在需要 cookie 才能正常运行的 Web 服务中遇到了类似的问题。显然,Jelly Bean 默认不会自动创建 cookie 存储(与以前的版本不同),因此该服务无法找到我的会话,并且每次我尝试访问它时都会抛出 401。在我的应用程序初始化中添加以下代码行可以解决问题:

        // enable VM-wide cookie support for HttpUrlConnection
        // see http://developer.android.com/reference/java/net/HttpURLConnection.html for details
        CookieManager cookieManager = new CookieManager();
        CookieHandler.setDefault(cookieManager);
        

        【讨论】:

          【解决方案6】:

          当使用基本身份验证而不调用 setDoOutput(true) 时,我们仍然遇到这个问题:

          解决办法如下:

          HTTP Basic Authentication issue on Android Jelly Bean 4.1 using HttpURLConnection

          【讨论】:

            【解决方案7】:

            检查您的服务器是否返回Error 401 - Not Authorised。我相信 Android 代码会看到该响应,并认为它旨在提供身份验证详细信息。就我而言,我只是向我的服务器提供了错误的令牌。

            【讨论】:

              【解决方案8】:

              只有一个解决方案

              在你的代码中删除这个

              HttpConnection.setDoOutput(true);

              它适用于ICSJelly Bean

              【讨论】:

                【解决方案9】:

                我为此使用的解决方案(我正在使用 Android 的 Volley 库)是使用 Square's OkHttp library。他们的实现正确处理了这个问题,并将按预期返回 401。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-09-05
                  • 2014-12-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-02-12
                  相关资源
                  最近更新 更多