2010-01-14 21 views
5

Tengo un servlet que permite a los usuarios descargar archivos zip (potencialmente grandes) desde una página web. Si el usuario hace clic en un enlace para descargar un archivo zip, código similar al siguiente se ejecuta en el servlet:Servlets de Java: la descarga de archivos se rompe cuando el usuario navega fuera de la página

response.setContentType("application/zip"); 
response.setHeader("Content-disposition", "attachment; filename=foo.zip"); 
response.setHeader("Pragma", ""); 
response.setHeader("Cache-Control", "no-store"); 

ZipOutputStream out = new ZipOutputStream(response.getOutputStream()); 
// write entries to the zip file... 
... 
out.close() 

Sin embargo, si se actualiza el usuario o salga de la página después de que comience la descarga y antes de que completa (en Firefox 3.5.7), la descarga fallará. El siguiente error aparece:

C: \ bla \ foo.zip.part no podía ser salvado , debido a que el archivo de origen podría no se puede leer.

Vuelva a intentarlo más tarde o póngase en contacto con el administrador del servidor .

¿Alguna idea sobre cómo puedo asegurarme de que la descarga continúe en este caso?

ACTUALIZACIÓN: El enlace que inicia la descarga es un simple enlace de vainilla. Curiosamente, el comportamiento es diferente en IE. Al hacer clic en los enlaces en cualquier lugar del sitio (desde la pantalla cargada actualmente) parece que no se carga (la barra de estado del navegador dice "Esperando https://mysite/clicked_linky.do ..."), bloqueando hasta que finalice la descarga. Escribir una URL diferente en la barra de direcciones o usar un atajo/enlace favorito navega fuera de la página, pero la descarga continúa como se esperaba. Solo Firefox parece mostrar el comportamiento exacto que describí anteriormente, aunque el bloqueo de IE no es óptimo.

Respuesta

6

Esto no debería suceder. La descarga cuenta como una solicitud separada que se supone que se ejecuta en segundo plano independientemente de la página principal una vez invocada. ¿Cómo está disparando exactamente la solicitud de descarga? ¿Por un simple enlace vainilla o un enlace que (incorrectamente) dispara una solicitud ajaxical para ejecutar la descarga?

En cualquier caso, al menos claramente desea reanudar descargas. En este caso, debe enviar al menos los encabezados de respuesta Accept-Ranges, ETag y Last-Modified a lo largo de la descarga en consecuencia. El cliente puede entonces solicitar reanudar la descarga enviando los encabezados de solicitud If-Range y Range con el identificador de archivo y un rango de bytes especificado que puede usar junto con RandomAccessFile para enviar los bytes restantes. Puede encontrar más información y una muestra de servlet en this article.

Esa es la teoría. En su caso particular, es un poco complicado cuando está comprimiendo los archivos sobre la marcha. Primero deberá escribir el archivo comprimido en una carpeta temporal del sistema de archivos del disco local del servidor y luego transmitirlo y finalmente eliminar el archivo solo cuando la descarga se haya completado correctamente (es decir, out.close() no arrojó IOException). Puede identificar el archivo zip asociado con la ayuda del parámetro de solicitud o pathinfo o tal vez una clave en la sesión.

Actualización: según su actualización: Honestamente, no lo sé y nunca lo he experimentado, pero al menos puedo decir que you're not the only one who suffered from this problem. Al menos, la implementación de las capacidades del currículum como se describió anteriormente puede ser una solución a este problema en particular, ya que Firefox automáticamente reanudaría la descarga sin sacudirse una parte incompleta.

Actualización 2: después de pensar un poco después de leer su actualización y los comportamientos del navegador, parece que hay un intervalo de tiempo bastante grande entre disparar la solicitud real y la llegada de los encabezados de respuesta. No sé los detalles exactos de cómo cargar los archivos, pero mira de modo que hay un costo de tiempo en la recopilación de los archivos ZIP (¿quizás los estás cargando desde un sistema de archivos o base de datos en red de antemano?) Y que establecer/enviar los encabezados de respuesta solo después de ha reunido todos los archivos ZIP. Intente configurar los encabezados y hacer output.flush()antes de haciendo la costosa tarea. De esta forma, el navegador obtendrá los encabezados tan pronto como sea posible y sabrá lo que puede esperar.

+0

Estoy de acuerdo, una solicitud de descarga independiente servlet debe no se equivoque si el cliente lleva el navegador a otra página, o lo actualiza. Implementé un servlet de descarga en Java y no experimenté ninguno de estos problemas. –

+0

Es un simple enlace vainilla. Actualicé la pregunta. – Jeff

0

Sospecho que es un artefacto del uso de servlets, probablemente como resultado de la reasignación del hilo. Ciertamente no tengo ese problema con una configuración similar escrito en PHP (en la que cada solicitud es manejada por un (efectivamente) nuevo proceso.

HTH

C.

Cuestiones relacionadas