HttpURLConnection отлично работает в Android 2.x, но НЕ в 4.1: не обнаружены проблемы аутентификации
У меня есть некоторые типичные коды, которые использовали 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)
...
Ответы
Ответ 1
В настоящее время я сталкиваюсь с той же проблемой. On 4.1 Jelly Bean Я получаю IOException "Нет проблем с проверкой подлинности" при вызове метода getResponseCode() в HttpURLConnection.
Я искал онлайн, чтобы узнать, что изменилось в исходном коде 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. Он анализирует заголовки задач, которые он находит в ответе, используя HeaderParser.parseChallenges(..), если код ответа равен 401 или 407. Если возвращенный список пуст, возникает исключение.
https://bitbucket.org/seandroid/libcore/src/6b27266a2856/luni/src/main/java/libcore/net/http/HeaderParser.java
В настоящее время мы расследуем то, что именно заставляет этот список быть пустым, но есть подозрение, что наш сервер может использовать realm =... вместо realm = "..." в заголовке запроса. Причиной этой проблемы может быть отсутствие пропущенных кавычек. Мы должны продолжить исследование, если это действительно так, и если мы сможем заставить его работать.
Ответ 2
Per RFC2617:
Ответное сообщение 401 (неавторизованное) используется сервером происхождения чтобы оспорить авторизацию пользовательского агента. Этот ответ ДОЛЖЕН включают поле заголовка WWW-Authenticate, содержащее по крайней мере один вызов, применимый к запрашиваемому ресурсу.
В Android метод HttpURLConnection getResponseCode() вызывает java.io.IOException: No authentication challenges found
, когда сервер возвращает либо код состояния 401 Unauthorized
, либо 407 Proxy Authentication Required
без WWW-аутентификации набор заголовков.
Если у вас есть API-интерфейс на стороне сервера, вы можете исправить его, добавив требуемый заголовок WWW-Authenticate при возврате 401 или 407. В моем случае я исправил его на PHP следующим образом:
header('WWW-Authenticate: OAuth realm="users"');
header('HTTP/1.1 401 Unauthorized');
Ответ 3
У меня та же проблема. Я нашел это обходное решение, но он не работает на Android 2. На желе Bean он отлично работает. Просто используйте getErrorStream() вместо getInputStream().
try
{
responseStream = new BufferedInputStream(connection.getInputStream());
}
catch(IOException e)
{
responseStream = new BufferedInputStream(connection.getErrorStream());
}
Ответ 4
Заголовок
Я исправил проблему для Желе bean. Для приведенного выше сценария используйте приведенный ниже код.
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 работали корректно. Очевидно, что 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 на Android Jelly Bean 4.1 с использованием HttpURLConnection
Ответ 7
Проверьте, возвращает ли ваш сервер Error 401 - Not Authorised
. Я считаю, что код Android видит этот ответ и полагает, что он предназначен для предоставления сведений об аутентификации. В моем случае я просто предоставлял неверный токен моему серверу.
Ответ 8
Существует одно решение
В вашем коде Удалите это
HttpConnection.setDoOutput(true);
Он будет работать на ICS
или Jelly Bean
Ответ 9
Решение, которое я использовал для этого (я использую библиотеку Android Volley), должно было использовать
Квадратная библиотека OkHttp. Их реализация правильно обрабатывает эту проблему и вернет 401, как ожидалось.