2010-07-28 11 views
11

Saludos,provocando una descarga de archivos sin ningún tipo de solicitud del servidor

estoy trabajando en una aplicación basada en JS que hace un trabajo complejo y registra alguna información (en realidad, hasta cientos de líneas) en un <div>.

Mi objetivo es tener un botón "Guardar registro" que activa el diálogo de descarga del navegador para guardar el contenido de mi registro <div>.

más concisa, estos son los requisitos para esta función:

  • El usuario final debe tener un control total sobre el archivo. Debería ser capaz de guardarlo/archivarlo para referencia futura, enviarlo por correo al departamento de soporte para obtener ayuda para solucionar algún problema, cargarlo nuevamente en la aplicación, etc. Así que la API de almacenamiento web de HTML5 no ayuda aquí (los datos obtener guardado en una ubicación definida por el navegador y no sería fácilmente recuperable, excepto desde el JS que lo crea).
  • La aplicación debe poder funcionar sin conexión (al menos en algunas circunstancias). Eso, y la eficiencia, es la razón por la que descarté la idea de PUBLICAR los datos en el servidor para recuperarlos con un encabezado de "disposición de contenido".
  • El archivo debe marcarse correctamente como text/plain, por lo que el navegador puede sugerir acciones predeterminadas (como "Abrir en el bloc de notas") igual que con una descarga normal de archivos. Esto se puede ver como un aspecto específico del primer requisito.
  • Decirle al usuario que copie y pegue el contenido de <div> en un editor de texto y guardarlo definitivamente es horrible, y es exactamente por eso que trato de evitarlo.

He estado buscando en este sitio, en los sitios WHATWG y W3C y en la web en general sin éxito. ¿Esto es factible?

Lo más cercano que tengo es usando una url data:. Mi primer intento, realizar una acción POST, no pudo obtener un tipo de contenido, por lo que retrocedería a la heurística de la UA. Lo conseguí un poco mejor diseñando un enlace <a> para que pareciera un botón y le diera un atributo type, pero entonces el UA jugará de forma demasiado inteligente y renderizará el contenido en lugar de guardarlo (y le pedirá al usuario que guarde el archivo desde el navegador en ese paso es incluso peor que tomar el enfoque de copiar y pegar, ya que el ahorro de página varía enormemente entre navegadores).

Si hubiera alguna forma de combinar una url data: con una sugerencia similar a la de "disposición de contenido", las cosas podrían ir realmente bien.

Saludos, Herenvardo

+1

¿Está utilizando un complemento como Flash sin la pregunta? No sé si es posible hacerlo con HTML estándar, pero sería bastante fácil si Flash fuera una opción ... –

+0

Tenía una pregunta similar http://stackoverflow.com/questions/2832392/can-you- do-file-io-using-javascript-without-activex pero solo tiene una respuesta. No creo que sea posible sin embargo. –

+0

¿Apareció la "copia en el portapapeles con código y pidiéndole al usuario que la pegue en una libreta (o editor de texto favorito)"? El portapapeles puede manejar megabytes, aunque el bloc de notas podría ahogarse en algunos megabytes. Por otro lado: vea http://stackoverflow.com/questions/17836273/export-javascript-data-to-csv-file-without-server-interaction – TWiStErRob

Respuesta

2

Desafortunadamente esto no es algo que puede hacer con capacidades normales del navegador. Algo como el flash o un complemento específico del navegador le proporcionará lo que necesita, pero las limitaciones de seguridad en javascript no le permitirán descargar datos arbitrarios creados dentro del navegador.

Además, la URL de 'datos' no es compatible con todas las combinaciones de navegador/versión. No estoy seguro si sus usuarios están limitados en qué navegador están usando o no, pero eso puede limitar lo que puede hacer con esa solución.

+0

¡Gracias! Parece que el enfoque basado en plug-in (o Flash) es la única forma en que se pueden cumplir todos los requisitos. En una nota lateral, el soporte para 'datos:' no es un gran problema: la aplicación en su conjunto depende de muchas funciones HTML5, por lo que ya existe un requisito de navegador pesado, que requiere soporte para 'datos:' ganó ' Es un gran problema. –

+1

Además, Silverlight puede ser una opción viable aquí. –

2

Esta solución es un poco intrincada pero funcionaría para sus necesidades, quizás sea una opción.

Crea un servidor web personalizado que simplemente devuelve el contenido de cualquier GET o POST como texto/plano.

Aloje ese servidor web en la misma caja que la aplicación web pero ejecutándolo en un puerto diferente. Cuando hace clic en el botón Guardar registro, la solicitud se envía al servidor personalizado y se devuelve el archivo de texto.

He aquí una prueba de servidor concepto en Java que hará exactamente eso:

// After running this program, access with your browser at 127.0.0.1:8080 

import java.net.*; 
import java.io.*; 

public class ReturnTextFile 
{ 

    public static void main(String[] args) 
    { 

    try 
    { 
     ServerSocket server = new ServerSocket(8080); 
     Socket connection = null; 

     while (true) 
     { 

     try 
     { 
      connection = server.accept(); 

      BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); 

      String input = in.readLine(); 

      // TODO: Clean up input 

      Writer out = new OutputStreamWriter(connection.getOutputStream()); 

      String output = "HTTP/1.1 200 OK\n" + 
        "Connection: close\n" + 
        "Content-Disposition: attachment; filename=log.txt\n" + 
        "Content-Type: text/plain; charset=utf-8\n" + 
        "\n"; 

      output += input; 

      out.write(output); 

      out.flush(); 

      connection.close(); 
     } 
     catch (IOException ex) 
     { 
      ex.printStackTrace(); 
     } 
     finally 
     { 
      if (connection != null) 
      { 
      connection.close(); 
      } 
     } 

     } 

    } 
    catch (IOException ex) 
    { 
     ex.printStackTrace(); 
    } 

    } 
} 
+0

+1 para un enfoque tan interesante. Definitivamente voy a tener en mente la idea de un servidor local para proyectos futuros, pero la respuesta de Mike parece resolver el problema mucho más fácilmente. –

2

Puede establecer el tipo de contenido en la URL data:, algo como esto:

data:text/plain,this is some text 

Sin embargo, eso todavía tiene el problema de que el navegador lo representa automáticamente como texto. Realmente tienes dos opciones que puedo ver. Una es que configure el tipo de tipo binario para que el navegador no intente procesarlo, o que tenga el tipo de texto/sin formato y haga que el usuario haga clic con el botón derecho y lo guarde. Tal vez algo here puede ayudar?

1

He estado en este camino, y también quería hacerlo puramente en el lado del cliente. Pero es imposible. La única manera en que puede activar el diálogo de guardar sin ningún problema es haciendo una solicitud HTTP POST y haciendo que el servidor responda con un encabezado content-disposition.

Tengo su funcionalidad deseada en los fragmentos de código en my dusty old blog. Tengo un formulario con un campo oculto apuntando a un controlador HTTP personalizado. JavaScript toma el texto interno del bloque de código, lo coloca en el campo oculto y envía el formulario. El servidor responde con todo el cuerpo de la solicitud, junto con los encabezados necesarios. Sin actualización, haga clic en él y obtendrá un diálogo de guardar. ¡Funciona genial!

+0

¿Qué hay de usar un encabezado 'http-equiv' en unión con un URI' data: 'para simular el encabezado? Funcionaría eso? – haxxerz

Cuestiones relacionadas