安卓 - Volley 错误:未找到身份验证挑战

11

我正在尝试处理一些旧代码,并在使用volley时遇到问题。

我正在尝试访问我们主站点的api,对于一个账户它能正常工作,但另外一个却不行。我试图弄清楚请求URL/头信息之间的差异以及响应中返回的内容,但我无法找到在volley代码中打印日志的方法。

我收到的错误信息是:

com.android.volley.NoConnectionError: java.io.IOException: No authentication challenges found

我看到有人说这可能是由于401响应引起的,但我不太清楚其含义或者如何证明/测试。我真的很困惑,因为它可以用一个帐户而另一个则不行。

网址略有不同,一个是我们的英国站点,另一个是我们的AM站点,但除此之外没有任何区别。

谢谢


这是一个错误,表示在执行Volley请求时无法建立连接。 - Raghunandan
@bbalazs 我不认为那有帮助,我已经读过了。我不认为那与Volley有关。 - Russ Wheeler
@Raghunandan,是什么让你认为无法建立连接?我认为这是由于身份验证不匹配。 - Russ Wheeler
@RussWheeler,请查看源代码 `@SuppressWarnings("serial") public class NoConnectionError extends NetworkError { public NoConnectionError() { super(); }public NoConnectionError(Throwable reason) { super(reason); }}`,并且有一条注释说:/**
  • 表示在执行Volley请求时无法建立连接的错误。 */
- Raghunandan
这与网络连接无关,当收到401响应时,在响应头中读取时出现错误。请参见此处:https://dev59.com/AmnWa4cB1Zd3GeqP3LS8 - Patrick
显示剩余2条评论
5个回答

8
事实上,我解决了这个问题,方法是在服务器响应中包含WWW-Authenticate 头信息。然而,如果你添加头信息WWW-Authenticate: Basic realm=""并且你的API也被web客户端使用,一些Web浏览器会触发一个弹出窗口来要求基本凭据。
对我来说,正确的解决方案是使用自定义协议。正如这篇博客文章所解释的那样,我在头响应中使用xBasic而不是BasicWWW-Authenticate: xBasic realm="" 有了这个头信息,不仅Volley可以正确解析响应,我也可以避免Web浏览器显示身份验证弹出窗口。

非常抱歉我提出了这个问题,因为它是很久以前的事情了,我甚至都不记得它与什么有关系了,而且那个遗留项目已经关闭了。我会为你所付出的努力点赞,但是我无法验证它是否正确,所以恐怕不能选择它作为答案。 - Russ Wheeler
@Russ 没问题!只是想帮助其他寻找答案的人 :) - Xavi Gil
只是附带一下注意事项。您可以使用任何字符串作为方案(例如,如上所示的 xBasic),但必须包括 realm=""(包括引号)以避免抛出异常。 - Paul LeBeau
如何在服务器响应中添加WWW-Authenticate头部 - sss

8

这个错误是因为服务器发送了一个401(未授权)但没有给出“WWW-Authenticate”,这是一个提示客户端下一步该做什么的提示。 “WWW-Authenticate”标头告诉客户端需要哪种身份验证(BasicDigest)。这在无头HTTP客户端中通常不是很有用,但这就是标准定义的方式。错误发生是因为库尝试解析“WWW-Authenticate”标头但无法解析。

如果您可以更改服务器,则可能的解决方案:

  • 添加一个虚假的“WWW-Authenticate”标头,如:WWW-Authenticate:Basic realm =“fake”。这只是一个解决方法而不是解决方案,但它应该有效并且HTTP客户端满意。
  • 使用HTTP状态代码403而不是401。它的语义不同,通常在使用登录时401是正确的响应(请参阅此处进行详细讨论),但足够接近。

如果您无法更改服务器,则可能的解决方案:

正如@ErikZ在他的post中所写的那样,您可以使用try&catch。

HttpURLConnection connection = ...;
try {
    // Will throw IOException if server responds with 401.
    connection.getResponseCode(); 
} catch (IOException e) {
    // Will return 401, because now connection has the correct internal state.
    int responsecode = connection.getResponseCode(); 
}

我也在这里发布了:java.io.IOException : 没有找到身份验证挑战


我正在尝试使用摘要认证发送头文件,但无法弄清如何实现(仍在寻找答案)。您有没有Android-Volley中如何进行摘要(甚至基本)认证的示例? - Michel Ayres
Basic和Digest只是在头部添加一个看起来像这样的标题:“Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==”,在基本认证中比较简单,在摘要认证中则更加复杂 - 这不是Volley特有的,您只需设置标题(在Volley中如何设置请参考Google)。 - Patrick
非常抱歉我提出了这个问题,因为它是很久以前的事情,我甚至不记得它与什么有关系,而且那个遗留项目已经关闭了。我会为你所付出的努力点赞,但是我无法验证它是否正确,所以恐怕不能选择它作为答案。 - Russ Wheeler
好的,没问题。既然我花了很长时间才理解这个问题——学习REST/HTTP规范有时候并不像你想象的那么直接明了 :) - Patrick
如何在服务器响应中添加WWW-Authenticate头 - sss

0

当初始化 Volley RequestQueue 时,我能够在客户端捕获到这个问题:

Volley.newRequestQueue(getApplicationContext(), new HurlStack() {
        @Override
        public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) {
            try {
                return super.performRequest(request, additionalHeaders);
            } catch (AuthFailureError authFailureError) {
                authFailureError.printStackTrace();
                // Log out / whatever you need to do here
            } catch (IOException e) {
                e.printStackTrace();
                if (e.getMessage().equals("No authentication challenges found")) {
                    // This is the error.  You probably will want to handle any IOException, not just those with the same message.
                }
            }
            return null;
        }
});

0

你可以检查 e 是否是 AuthFailureError 的实例。

Log.e(TAG, "AuthFailureError: " + (e instanceof AuthFailureError));

0
如果服务器崩溃,您可能会遇到这个问题。 步骤: 1. 停止Tomcat服务器 2. 转到运行 -> 服务 -> 重新启动您的数据库(例如:PostgreSQL) 3. 启动Tomcat服务器。

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