2011-06-29 17 views
44

Todo funciona bien, pero solo si el archivo es pequeño, aproximadamente 1MB, cuando lo probé con archivos más grandes, como 20MB mi navegador lo muestra, en lugar de forzar la descarga, intenté muchos encabezados hasta ahora, ahora mi código se ve:Cómo forzar al navegador a descargar el archivo?

PrintWriter out = response.getWriter(); 
String fileName = request.getParameter("filename"); 

File f= new File(fileName); 

InputStream in = new FileInputStream(f); 
BufferedInputStream bin = new BufferedInputStream(in); 
DataInputStream din = new DataInputStream(bin); 

while(din.available() > 0){ 
    out.print(din.readLine()); 
    out.print("\n"); 
} 

response.setContentType("application/force-download"); 
response.setContentLength((int)f.length()); 
response.setHeader("Content-Transfer-Encoding", "binary"); 
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName); 


in.close(); 
bin.close(); 
din.close(); 
+0

Configurando el tipo de contenido debería hacerlo. ¿Qué navegador es? –

+0

¿Qué navegador? Octet-stream debería ser la respuesta correcta, pero las versiones anteriores de IE solían intentar "olfatear" el tipo de contenido independientemente de lo que el servidor web le decía – Paolo

+0

chrome, ff 3.6, y cualquier otro probablemente ... – dieeying

Respuesta

60

Está configurando los encabezados de respuesta después de escribir el contenido del archivo en la secuencia de salida. Esto es bastante tarde en el ciclo de vida de la respuesta para establecer los encabezados. La secuencia correcta de operaciones debería ser establecer primero los encabezados y luego escribir el contenido del archivo en la salida del servlet.

Por lo tanto, el método debe ser escrito de la siguiente manera (esto no va a compilar ya que es una mera representación):

response.setContentType("application/force-download"); 
response.setContentLength((int)f.length()); 
     //response.setContentLength(-1); 
response.setHeader("Content-Transfer-Encoding", "binary"); 
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName); 
... 
... 
File f= new File(fileName); 

InputStream in = new FileInputStream(f); 
BufferedInputStream bin = new BufferedInputStream(in); 
DataInputStream din = new DataInputStream(bin); 

while(din.available() > 0){ 
    out.print(din.readLine()); 
    out.print("\n"); 
} 

La razón del fracaso es que es posible que los encabezados reales enviados por el servlet sería diferente de lo que está intentando enviar. Después de todo, si el contenedor de servlets no sabe qué encabezados (que aparecen antes del cuerpo en la respuesta HTTP), puede establecer encabezados apropiados para garantizar que la respuesta sea válida; configurar los encabezados después de que se haya escrito el archivo es, por lo tanto, inútil y redundante, ya que el contenedor puede haber configurado los encabezados. Puede confirmar esto mirando el tráfico de red usando Wireshark o un proxy de depuración HTTP como Fiddler o WebScarab.

También puede consultar la documentación de la API de Java EE para ServletResponse.setContentType para entender este comportamiento:

establece el tipo de contenido de la respuesta que se envía al cliente, si la respuesta no se ha confirmado todavía. El tipo de contenido dado puede incluir una especificación de codificación de caracteres, por ejemplo, text/html; charset = UTF-8. La codificación de caracteres de la respuesta solo se establece desde el tipo de contenido dado si se llama a este método antes de llamar a getWriter.

Este método se puede llamar repetidamente para cambiar el tipo de contenido y la codificación de caracteres. Este método no tiene efecto si se invoca después de que se ha confirmado la respuesta.

...

+0

application/force-download es un truco, no un estándar: http://www.media-division.com/the-right-way-to-handle-file -downloads-in-php/ –

+0

@ChristopheRoussy, sí nadie reclamó como tal. Deja de enviar spam aquí todas las respuestas. –

+2

Quiero informar a otros usuarios de SO sobre que es un truco y cómo funciona, ya que no se menciona en ninguna parte, aquí hay una explicación sobre SO: http://stackoverflow.com/questions/10615797/utility-of-http-header -content-type-application-force-download-for-mobile –

3

Esto es de un script php que resuelve el problema perfectamente con todos los navegadores que he probado (FF desde 3.5, Internet Explorer 8 +, Chrome)

header("Content-Disposition: attachment; filename=\"".$fname_local."\""); 
header("Content-Type: application/force-download"); 
header("Content-Transfer-Encoding: binary"); 
header("Content-Length: ".filesize($fname)); 

Así que por lo que yo puedo ver, usted' haciendo todo correctamente ¿Has revisado la configuración de tu navegador?

+0

Me encantan los votos acumulados sin una explicación ... – f1sh

+5

Supongo que es "estás haciendo todo correctamente" que te quemó. La respuesta aceptada deja en claro lo que fue incorrecto. –

+0

application/force-download es un truco, no es un estándar –

4

Conjunto de tipo de contenido y otras cabeceras antes se escribe el archivo de salida. Para archivos pequeños, el contenido se almacena en el búfer y el navegador obtiene los encabezados primero. Para grandes, los datos son lo primero.

+0

Esto es un poco crítico de información, aprendí de la manera difícil :) – ragebiswas

Cuestiones relacionadas