2011-02-25 11 views
7

Mi código (reproducido a continuación), se conecta a una url y descarga el archivo en el disco en Android. Todo lo estándar. Cuando intento usar este código en un archivo en S3 al que se accede a través de un subdominio en nuestro servidor mapeado a un segmento (por ejemplo, foo.example.com => cubo llamado foo.example.com), a menudo falla. Resulta que (mediante el comando útil rizo ..Android/Java: HttpURLConnection no devuelve los encabezados del archivo redirigido (por ejemplo, en S3)

"curl -v -L -X GET http://foo.example.com/f/a.txt") 

.. que hay una redirección pasando aquí.

El archivo de descarga funciona bien, como HttpURLConnection seguirán las redirecciones de forma predeterminada, pero las llamadas que requieren la infomación cabecera (getContentLength, getHeaderFieldDate ("Last-Modified", 0), etc) son declaraciones de las cabeceras de los 307 redirección, y no los que eso es real de los archivos descargados.

Alguien sabe cómo conseguir alrededor de esto?

Gracias

File local = null; 
     try { 


      Log.i(TAG, "Downloading file " + source); 
      conn = (HttpURLConnection) new URL(source).openConnection(); 
      fileSize = conn.getContentLength(); // ** THIS IS WRONG ON REDIRECTED FILES 
      out = new BufferedOutputStream(new FileOutputStream(destination, false), 8 * 1024); 
      conn.connect(); 

      stream = new BufferedInputStream(conn.getInputStream(), 8 * 1024); 

      byte[] buffer = new byte[MAX_BUFFER_SIZE]; 

      while (true) { 
       int read = stream.read(buffer); 

       if (read == -1) { 
        break; 
       } 
       // writing to buffer 
       out.write(buffer, 0, read); 
       downloaded += read; 

       publishProgress(downloaded, fileSize); 

       if (isCancelled()) { 
        return "The user cancelled the download"; 
       } 

      } 
     } catch (Exception e) { 
      String msg = "Failed to download file " + source + ". " + e.getMessage(); 
      Log.e(TAG, msg); 
      return msg; 
     } finally { 
      if (out != null) { 
       try { 
        out.flush(); 
        out.close(); 
       } catch (IOException e) { 
        Log.e(TAG, "Failed to close file " + destination); 
        e.printStackTrace(); 
       } 
      } 

      if (stream != null) { 
       try { 
        stream.close(); 
       } catch (IOException e) { 
        Log.e(TAG, "Failed to close file " + destination); 
        e.printStackTrace(); 
       } 

      } else { 

       long dateLong = conn.getHeaderFieldDate("Last-Modified", 0); // ** THIS IS WRONG ON REDIRECTED FILES 

       Date d = new Date(dateLong); 
       local.setLastModified(dateLong); 
      } 

Respuesta

10

¿Ha intentado establecer los redireccionamientos en falso y tratar de capturar manualmente la URL redirigida y los campos de encabezado asociados con ella?

Por ejemplo algo como esto:

URL url = new URL(url); 
HttpURLConnection ucon = (HttpURLConnection) url.openConnection(); 
ucon.setInstanceFollowRedirects(false); 
URL secondURL = new URL(ucon.getHeaderField("Location")); 
URLConnection conn = secondURL.openConnection(); 

Este ejemplo captura la URL redirigida, pero se puede modificar fácilmente esto para tratar de cualquier otro campo de la cabecera. ¿Esto ayuda?

+0

gracias. Supongo que sería un poco complicado con múltiples redireccionamientos, pero eso bien puede ayudar –

+1

Me he encontrado con otros errores extraños en el código de redireccionamiento de varios componentes de Android. Incluso en la misma versión del sistema operativo, diferentes dispositivos los manejarían de manera diferente. Cambiamos a redirección manual como resultado. –

+0

Ah, interesante. He estado experimentando con el uso de apache HttpClient en lugar de HttpURLConnection, y ha estado funcionando para mí (¡hasta ahora!). ¿Con qué componentes de Android has tenido problemas? –

0

Bueno, he estado jugando un poco y este código, que utiliza la biblioteca HttpClient en lugar de HttpUrlConnection funciona bien. Los encabezados que devuelve son los del salto de redirección final. Al menos en los dispositivos en los que lo he probado.

HttpClient client = null; 
HttpGet get = null; 
HttpResponse response = null; 
try { 
client = new DefaultHttpClient(); 
get = new HttpGet(source); 
response = client.execute(get); 

Header contentSize = response.getFirstHeader("Content-Length"); 
if (contentSize != null) { 
String value = contentSize.getValue(); 
fileSize = Long.parseLong(value); 
} 
if (fileSize == -1) { 
    Log.e(TAG, "Failed to read the content length for the file " + source); 
} 

Header lastModified = response.getFirstHeader("Last-Modified"); 
lastModifiedDate = null; 
if (lastModified != null) { 
    lastModifiedDate = DateUtils.parseDate(lastModified.getValue()); 
} 
if (lastModifiedDate == null) { 
    Log.e(TAG, "Failed to read the last modified date for the file " + source); 
} 

out = new BufferedOutputStream(new FileOutputStream(destination, false), 8 * 1024);  // false means don't append 
stream = new BufferedInputStream(response.getEntity().getContent(), 8 * 1024); 

byte[] buffer = new byte[MAX_BUFFER_SIZE]; 

int count = 0; 
while (true) { 
    int read = stream.read(buffer); 

    if (read == -1) { 
     break; 
    } 
    // writing to buffer 
    out.write(buffer, 0, read); 
    downloaded += read; 

    publishProgress(downloaded, fileSize); 

    if (isCancelled()) { 
     Log.w(TAG, "User Cancelled"); 
     return; // NOTE that onPostExecute is not called here.. 
    } 
}// end of while 

publishProgress(downloaded, fileSize); 

} catch (Exception e) { 
String msg = "Failed to download file " + source + ". " + e.getMessage(); 
Log.e(TAG, msg); 
return msg; 
} finally { 
if (out != null) { 
    try { 
     out.flush(); 
     out.close(); 
    } catch (IOException e) { 
     Log.e(TAG, "Failed to close file " + destination); 
     e.printStackTrace(); 
    } 
} 

if (stream != null) { 
    try { 
     stream.close(); 
    } catch (IOException e) { 
     Log.e(TAG, "Failed to close file " + destination); 
     e.printStackTrace(); 
    } 
} 
} 
1

Considere el uso de httpclient-android. Usted debe obtener las cabeceras justo después de redirección con esto:

HttpClient client = HttpClientBuilder.create().build(); 
HttpGet request = new HttpGet(YOUR_URL); 
HttpResponse response = client.execute(request); 
response.getAllHeaders() 

Tenga en cuenta que Android viene con una versión anterior de httpclient, pero tiene el mismo problema que usted informó. Usted actually need para importar "httpclient-android" para una versión más nueva.

Nota: El fragmento de código es para v4.3. Para otras versiones, busque cómo hacerlo en Apache HttpClient regular.

Cuestiones relacionadas