java.io.IOException:没有发现authentication的挑战

我是Android的新手,这是我在android上的第一个项目。 我正在为“authentication”问题挣扎一天以上。 我尝试了几个选项,但没有一个工作。

基本上,我想调用一个REST API并获得响应。 我相信在API中没有问题,因为我在另一个iOS应用程序中使用相同的问题。

我通过授权标题,但仍authentication没有find消息显示。 我发现有关这个stackoverflow几个问题,但其中一些没有工作,有些对我来说没有意义。

我得到状态代码401 。 我知道这意味着要么没有身份validation通过,要么通过,那么他们是错的。 在这里,我确定我通过的是正确的。

以下是我的代码:

 try { url = new URL(baseUrl); } catch (MalformedURLException me) { Log.e(TAG, "URL could not be parsed. URL : " + baseUrl + ". Line : " + getLineNumber(), me); me.printStackTrace(); } try { urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod(method); urlConnection.setConnectTimeout(TIMEOUT * 1000); urlConnection.setChunkedStreamingMode(0); // Set HTTP headers String authString = "username:password"; String base64Auth = Base64.encodeToString(authString.getBytes(), Base64.DEFAULT); urlConnection.setRequestProperty("Authorization", "Basic " + base64Auth); urlConnection.setRequestProperty("Accept", "application/json"); urlConnection.setRequestProperty("Content-type", "application/json"); if (method.equals("POST") || method.equals("PUT")) { // Set to true when posting data urlConnection.setDoOutput(true); // Write data to post to connection output stream OutputStream out = urlConnection.getOutputStream(); out.write(postParameters.getBytes("UTF-8")); } try { // Get response in = new BufferedInputStream(urlConnection.getInputStream()); } catch (IOException e) { Log.e(TAG, "Exception in getting connection input stream. in : " + in); e.printStackTrace(); } // Read the input stream that has response statusCode = urlConnection.getResponseCode(); Log.d(TAG, "Status code : " + statusCode); } catch (ProtocolException pe) { pe.printStackTrace(); } catch (IllegalStateException ie) { ie.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { urlConnection.disconnect(); } 

看看logcat的截图:

logcat的

任何帮助,将不胜感激。 谢谢。

Solutions Collecting From Web of "java.io.IOException:没有发现authentication的挑战"

发生此错误是因为服务器发送401(未授权),但不给WWW-Authenticate头,这是提示客户下一步该怎么做。 WWW-Authenticate头部告诉客户端需要哪种authentication( Basic或Digest )。 这对于无头http客户端来说可能不是很有用,但是这就是HTTP 1.1 RFC的定义 。 发生该错误是因为lib试图parsingWWW-Authenticate头,但不能。

从RFC:

(…)响应必须包含一个WWW-Authenticate头域(14.47节),其中包含一个适用于所请求资源的挑战(…)

如果您可以更改服务器可能的解决scheme:

  • 添加一个假的“WWW-Authenticate”标头,如: WWW-Authenticate: Basic realm="fake" 。 这只是一个解决方法,不是一个解决scheme,但它应该工作,http客户端是满意的( 见这里讨论你可以放在头上 )。 但是请注意,一些http客户端可能会自动重试导致多个请求的请求(例如,频繁地增加错误的login次数)。 这是用iOS的http客户端观察到的。
  • 正如这个博客中的loudvchar所提出的,为了避免在浏览器中popuplogin表单这样的自动响应,您可以使用非标准的身份validation方法,如下所示: WWW-Authenticate: xBasic realm="fake" 。 重要的一点是, realm必须包括在内。
  • 使用HTTP状态代码403而不是401 。 它的语义是不一样的,通常当使用login401是一个正确的答案( 请参阅这里的详细讨论 ),但在兼容性方面更安全的解决scheme。

如果您不能更改服务器可能的解决scheme:

  • 正如@ErikZ在他的文章中写的,你可以使用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(); } 
  • 使用不同的http客户端,如OkHttp

你在testing什么版本的Android?

我在Gingerbread的一些开发工作中遇到了Androidvalidation器的问题(我不知道它在Android的更高版本上的performance是否有所不同)。 我使用Fiddler2来检查我的应用程序和服务器之间的HTTPstream量,发现authentication者没有为每个HTTP请求发送authenticationstring。 我需要它。

相反,我诉诸于此:

 urlConnection.setRequestProperty("Authorization", "Basic " + Base64.encodeToString("userid:pwd".getBytes(), Base64.NO_WRAP )); 

这是从我的代码中剪切粘贴的。 请注意,urlConnection是一个HttpURLConnection对象。

我在运行pre-KitKat Android的设备上遇到了相同的问题,但是我使用的是Volley库,所以@ for3st提供的客户端修复程序对我来说不起作用,我不得不调整它为Volley,在这里,希望它帮助有人解决这个问题:

 HurlStack hurlStack = new HurlStack() { @Override public HttpResponse performRequest(final Request<?> request, final Map<String, String> additionalHeaders) throws IOException, AuthFailureError { try { return super.performRequest(request, additionalHeaders); } catch (IOException e) { return new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), 401, e.getMessage()); } } }; Volley.newRequestQueue(context.getApplicationContext(), hurlStack); 

这样一个401错误返回,你的重试策略可以做它的工作(如请求令牌…等)。 虽然IOException可能是由其他问题引起的,但是除401之外,您可以select为Authorization关键字parsingexception消息,并为其他人返回不同的响应代码。

在一些旧设备上(例如华为Y330-U11)也有同样的问题。 正确的方法来解决它是解决它的服务器端在最stream行的答案中提到的。

但是,只有在某些设备上才会出现问题,这实在令人失望。 我相信这是由于“UrlConnection”的不同实现。 不同的Android版本 – 不同的“UrlConnection”实现。

所以,你可能想要通过在任何地方使用相同的“UrlConnection”来解决它。 尝试使用okhttp和okhttp-urlconnection。

以下是将这些库添加到您的Gradle构build中的方法:

 compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.squareup.okhttp:okhttp-urlconnection:2.5.0' 

它解决了那些过时设备上的问题。 (我不得不使用OkClient进行Retrofit RestAdapter)

PS最新的Androids在写作时使用旧版本的OKHTTP库作为“UrlConnection”实现(与更新的包名称),所以它似乎是相当稳固的东西