2012-07-31 13 views
14

Estoy usando HttpUrlConnection para realizar solicitudes de red desde mi aplicación de Android. Todo funciona bien, excepto una cosa, 401. Cuando el servidor devuelve la respuesta con el código de estado 401, mi aplicación arroja IOException con un mensaje que indica, "no authentication challenge found". Después de buscar en Google, no he encontrado una sola solución, sino solo una solución alternativa (manejarla usando try/catch, suponiendo que es una respuesta 401).Cómo obtener la respuesta 401 sin manejarlo usando try/catch en android

aquí es el fragmento de código:

public Bundle request(String action, Bundle params, String cookie) throws FileNotFoundException, MalformedURLException, SocketTimeoutException, 
     IOException { 

    OutputStream os; 

    String url = baseUrl + action; 
    Log.d(TAG, url); 
    HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); 
    conn.setConnectTimeout(30 * 1000); 
    conn.setReadTimeout(30 * 1000); 
    conn.setRequestProperty("User-Agent", System.getProperties().getProperty("http.agent") + "AndroidNative"); 
    conn.setRequestMethod("POST"); 
    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); 
    conn.setRequestProperty("Connection", "Keep-Alive"); 
    conn.setDoOutput(true); 
    conn.setDoInput(true); 
    if (cookie != null) { 
     conn.setRequestProperty("Cookie", cookie); 
    } 

    if (params != null) { 
     os = conn.getOutputStream(); 
     os.write(("--" + boundary + endLine).getBytes()); 
     os.write((encodePostBody(params, boundary)).getBytes()); 
     os.write((endLine + "--" + boundary + endLine).getBytes()); 
     uploadFile(params, os); 
     os.flush(); 
     os.close(); 
    } 

    conn.connect(); 

    Bundle response = new Bundle(); 
    try { 
     response.putInt("response_code", conn.getResponseCode()); 
     Log.d(TAG, conn.getResponseCode() + ""); 
     response.putString("json_response", read(conn.getInputStream())); 
     List<String> responseCookie = conn.getHeaderFields().get("set-cookie"); 
     // Log.d(TAG, responseCookie.get(responseCookie.size() - 1)); 
     response.putString("cookie", responseCookie.get(responseCookie.size() - 1)); 
    } catch (SocketTimeoutException e) { 
     throw new SocketTimeoutException(e.getLocalizedMessage()); 
    } catch (FileNotFoundException e) { 
     throw new FileNotFoundException(e.getLocalizedMessage()); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     response.putInt("response_code", HttpURLConnection.HTTP_UNAUTHORIZED); 
     response.putString("json_response", read(conn.getErrorStream())); 
    } 

    // debug 
    Map<String, List<String>> map = conn.getHeaderFields(); 
    for (String key : map.keySet()) { 
     List<String> values = map.get(key); 
     for (String value : values) { 
      Log.d(key, value); 
     } 
    } 

    conn.disconnect(); 

    return response; 
} 

Realmente quiero saber, ¿por qué esta excepción se lanza? ¿Qué significa desafío de autenticación? ¿Cómo proporcionar desafío de autenticación? ¿Qué cambio debo hacer en mi código para superar esta situación?

favor ilumíneme .. :)

+0

supongo que significa que el servidor responde con un código de error 401, pero omite la cabecera 'WWW-Authenticate' que describe el desafío de autenticación. El servidor – Jens

+0

tiene el encabezado 'WWW-Authenticate', pero aún recibo este error. – jtanveer

+0

Me acabo de topar con esto, y tampoco puedo encontrar la manera de recuperar este código de respuesta sin tener que asumir que es un 401 después de atrapar la IOException (ya que 'getResponseCode()' arrojará la misma IOException que 'connect()/getInputStream()/getOutputStream() '). Desde stacktrace, parece que 'org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.processAuthHeader (HttpURLConnectionImpl.java:1153) 'es responsable de arrojar la excepción por la cadena (aunque no pude bucear más). –

Respuesta

12

IOException es toda una excepción general, y no se puede asumir con seguridad un código de estado 401 cada vez que se lanza.

Si la primera vez que solicita el código de estado contiene un 401, HttpURLConnection lanzará una IOException. En este punto, el estado interno de la conexión habrá cambiado, y ahora podrá darle el código de estado, sin ningún error.

int status = 0; 
try { 
    status = conn.getResponseCode(); 
} catch (IOException e) { 
    // HttpUrlConnection will throw an IOException if any 4XX 
    // response is sent. If we request the status again, this 
    // time the internal status will be properly set, and we'll be 
    // able to retrieve it. 
    status = conn.getResponseCode(); 
} 
if (status == 401) { 
    // ... 
} 

Para más detalles, http://www.tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection

+0

Gracias por su respuesta. Como dijo, IOException es una excepción muy general. Se puede lanzar para cualquier cosa. de su respuesta, supongo que tengo que escribir otro bloque try/catch dentro del bloque try/catch principal para asegurarme de que se lanza la excepción debido a la recuperación del código de respuesta. En ese caso, ¡esto es otra vez una solución! Pero dado que ha pasado un año y no he encontrado ninguna solución, ¡estoy aceptando su respuesta! – jtanveer

+0

Esto solucionó el problema con la versión 4.2.2 de Android y bajo –

-2

tratar de utilizar HttpClient

private void setCredentials(String login, String password) { 
    if (login != null && password != null) 
     httpClient.getCredentialsProvider().setCredentials(
       new AuthScope(URL_HOST, 80), new UsernamePasswordCredentials(login, password)); 

} 



private InputStream execute(String url, String login, String password) { 
     setCredentials(login, password); 
     HttpGet get = new HttpGet(url); 
     try { 
      HttpResponse response = httpClient.execute(get); 
      int code = response.getStatusLine().getStatusCode(); 
      if (code == HttpURLConnection.HTTP_OK) { 
       InputStream stream = response.getEntity().getContent(); 
       return stream; 
      } else { 
       Log.e("TAG", "Wrong response code " + code + " for request " + get.getRequestLine().toString()); 
       return null; 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 
+2

Gracias por su respuesta. Pero realmente no quiero usar 'HttpClient' ya que no es muy liviano. En el caso de la carga de archivos, tendré que usar otra biblioteca de terceros ('MultipartEntity'), que no viene con SDK de Android. Necesito mantener el tamaño de apk pequeño. Además, Google sugiere usar 'HttpUrlConnection' porque es liviano y están trabajando activamente en eso. – jtanveer

Cuestiones relacionadas