Descargar archivo de url de datos

126

Estoy jugando con la idea de hacer una utilidad de descompresión / descompresión completamente basada en JavaScript a la que cualquiera pueda acceder desde un navegador. Simplemente pueden arrastrar su zip directamente al navegador y les permitirá descargar todos los archivos que contengan. También pueden crear nuevos archivos zip arrastrando archivos individuales.

Sé que sería mejor hacerlo en el servidor, pero este proyecto es solo por diversión.

Arrastrar archivos al navegador debería ser bastante fácil si aprovecho los diversos métodos disponibles. (Estilo Gmail)

La codificación / decodificación debería estar bien. He visto algunas bibliotecas as3 zip, así que estoy seguro de que debería estar bien con eso.

Mi problema es descargar los archivos al final.

window.location = 'data:jpg/image;base64,/9j/4AAQSkZJR....' 

Esto funciona bien en Firefox pero no en Chrome.

Puedo incrustar los archivos como imágenes muy bien en Chrome usando <img src="data:jpg/image;ba.." />, pero los archivos no serán necesariamente imágenes. Podrían ser de cualquier formato.

¿Alguien puede pensar en otra solución o algún tipo de solución?

Mikee
fuente
El soporte actual es, desafortunadamente, bastante limitado
Casebash

Respuestas:

42

Ideas:

  • Prueba un <a href="data:...." target="_blank">(no probado)

  • Utilice downloadify en lugar de URL de datos (también funcionaría para IE)

Pekka
fuente
@jcubic gracias por señalar el enlace muerto. La nueva ubicación de descarga parece ser github.com/dcneiner/Downloadify
Pekka
Si no puede usar Flash pero está ejecutando un componente del lado del servidor Java, puede usar esto: github.com/suprememoocow/databounce . Utiliza un Servlet para 'rebotar' los datos del cliente. Sería bastante fácil realizar el mismo truco en otras tecnologías del lado del servidor, como Python, ASP.NET, etc.
Andrew Newdigate
¿Hay alguna manera de hacerlo sin flash? ¿URL de datos para todos los navegadores pero IE y algún tipo de ActiveX foo para IE? (De esta forma logré reproducir música sin flash: audio HTML5 para todos los navegadores, excepto IE y ActiveX para IE).
panzi
Downloadify espera un reproductor flash en el navegador. Si el usuario no tiene reproductor de flash, el archivo no se descargará
Jeevanandan J
186

Si también desea dar un nombre sugerido al archivo (en lugar de la 'descarga' predeterminada) puede usar lo siguiente en Chrome, Firefox y algunas versiones de IE:

function downloadURI(uri, name) {
  var link = document.createElement("a");
  link.download = name;
  link.href = uri;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  delete link;
}

Y el siguiente ejemplo muestra su uso:

downloadURI("data:text/html,HelloWorld!", "helloWorld.txt");
owencm
fuente
66
Puede simplificar eso con en link.click()lugar de su eventFirefunción ... jsfiddle.net/ARTsinn/Ezx5m
yckart
3
Buena solución pero, ¿en qué se convierte el enlace?
webshaker
66
La variable 'enlace' sale del alcance al final de la función (tenga en cuenta que nunca la agregamos al dom), por lo que se recolectará basura poco después.
owencm
8
Esto solo funciona en Chrome. Si quieres que funcione en Firefox / IE mira la respuesta de @MartinoDino.
TrueWill
1
Intenté con download.js , como se sugiere aquí y parece funcionar. :)
joaorodr84
53

function download(dataurl, filename) {
  var a = document.createElement("a");
  a.href = dataurl;
  a.setAttribute("download", filename);
  a.click();
}

download("data:text/html,HelloWorld!", "helloWorld.txt");

o:

function download(url, filename) {
fetch(url).then(function(t) {
    return t.blob().then((b)=>{
        var a = document.createElement("a");
        a.href = URL.createObjectURL(b);
        a.setAttribute("download", filename);
        a.click();
    }
    );
});
}

download("https://get.geojs.io/v1/ip/geo.json","geoip.json")
download("data:text/html,HelloWorld!", "helloWorld.txt");

Zibri
fuente
haga clic en evento en elemento no existente: D no es necesario agregar appendchild.
Zibri
1
si. simplemente puede llamar a a.click () después de haber creado el elemento 'a', y luego configurar a's href.
user1709076
en el pasado, llamar a a.click () directamente no funcionaba pero funcionaba con el evento. Ahora ambos trabajan.
Zibri
1
Esto funciona en la mayoría de los navegadores modernos, pero debo señalar que agregar el documento y luego eliminarlo es necesario para admitir algunos navegadores más antiguos.
owencm
3
Su segunda solución debe usarse siempre que el dataUri sea demasiado grande (depende del navegador, pero Chrome no acepta Uri de múltiples megabytes en mi experiencia). Consulte también stackoverflow.com/questions/38781968/… .
neural5torm
27

Quiero compartir mi experiencia y ayudar a alguien atascado en las descargas que no funcionan en Firefox y la respuesta actualizada a 2014. El fragmento a continuación funcionará tanto en Firefox como en Chrome y aceptará un nombre de archivo:

  // Construct the <a> element
  var link = document.createElement("a");
  link.download = thefilename;
  // Construct the uri
  var uri = 'data:text/csv;charset=utf-8;base64,' + someb64data
  link.href = uri;
  document.body.appendChild(link);
  link.click();
  // Cleanup the DOM
  document.body.removeChild(link);
Martino Dino
fuente
44
Desafortunadamente, no funciona en Safari. Safari no parece reconocer el downloadatributo. Gracias de todos modos, esto es lo más cerca que puedo llegar en este momento.
Moritz Petersen
esto está causando que la ventana redirija al valor href para mí en IE 11. prevetDefault (); no detiene el comportamiento en IE
b_dubb 01 de
1
Gracias, también si btoano está definido (por ejemplo, en el proyecto frontend de nodo eslinado) const btxt = new Buffer(text).toString('base64'); const uri = 'data:text/csv;charset=utf-8;base64,' + btxt + ';'
Ivan Borshchov
2
eliminar el enlace no tiene sentido, queda fuera del alcance en la siguiente línea y se recolectará basura, no es un objetivo válido para eliminar.
macdja38
1
no es necesario document.body.appendChild ... mira mi respuesta stackoverflow.com/a/45905238/236062
Zibri
13

Aquí hay una solución de JavaScript pura que probé trabajando en Firefox y Chrome pero no en Internet Explorer:

function downloadDataUrlFromJavascript(filename, dataUrl) {

    // Construct the 'a' element
    var link = document.createElement("a");
    link.download = filename;
    link.target = "_blank";

    // Construct the URI
    link.href = dataUrl;
    document.body.appendChild(link);
    link.click();

    // Cleanup the DOM
    document.body.removeChild(link);
    delete link;
}

Soluciones de navegador cruzado encontradas hasta ahora:

descargar -> Requiere Flash

databounce -> Probado en IE 10 y 11, y no funciona para mí. Requiere un servlet y algo de personalización. (Detecta incorrectamente el navegador. Tuve que configurar IE en modo de compatibilidad para probar, juego de caracteres predeterminado en servlet, objeto de opciones de JavaScript con ruta de servlet correcta para rutas absolutas ...) Para navegadores que no son IE, abre el archivo en la misma ventana.

download.js -> http://danml.com/download.html Otra biblioteca similar pero no probada. Afirma ser JavaScript puro, no requiere servlet ni Flash, pero no funciona en IE <= 9.

Jesus MC
fuente
download.js es bastante bueno. Acabo de hacer una comprobación rápida en IE11, funciona. ¡Muchas gracias!
Ricky Jiao
12

Existen varias soluciones, pero dependen de HTML5 y todavía no se han implementado completamente en algunos navegadores. Los ejemplos a continuación se probaron en Chrome y Firefox (en parte funciona).

  1. Ejemplo de lienzo con soporte para guardar en archivo. Simplemente configure su document.location.hrefen el URI de datos.
  2. Ejemplo de descarga de anclaje . Se utiliza <a href="your-data-uri" download="filename.txt">para especificar el nombre del archivo.
Viacheslav Dobromyslov
fuente
3
ejemplo de lienzo conduce a 404
Karel Bílek
El atributo de descarga funciona para mí, para una url de datos pdf en Chrome y Safari móvil.
bbsimonbb
7

Combinando respuestas de @owencm y @ Chazt3n, esta función permitirá la descarga de texto de IE11, Firefox y Chrome. (Lo siento, no tengo acceso a Safari u Opera, pero agregue un comentario si lo intenta y funciona).

initiate_user_download = function(file_name, mime_type, text) {
    // Anything but IE works here
    if (undefined === window.navigator.msSaveOrOpenBlob) {
        var e = document.createElement('a');
        var href = 'data:' + mime_type + ';charset=utf-8,' + encodeURIComponent(text);
        e.setAttribute('href', href);
        e.setAttribute('download', file_name);
        document.body.appendChild(e);
        e.click();
        document.body.removeChild(e);
    }
    // IE-specific code
    else {
        var charCodeArr = new Array(text.length);
        for (var i = 0; i < text.length; ++i) {
            var charCode = text.charCodeAt(i);
            charCodeArr[i] = charCode;
        }
        var blob = new Blob([new Uint8Array(charCodeArr)], {type: mime_type});
        window.navigator.msSaveOrOpenBlob(blob, file_name);
    }
}

// Example:
initiate_user_download('data.csv', 'text/csv', 'Sample,Data,Here\n1,2,3\n');
kevinarpe
fuente
1

Para cualquiera que tenga problemas en IE:

Vota la respuesta aquí por Yetti: guardar el lienzo localmente en IE

dataURItoBlob = function(dataURI) {
    var binary = atob(dataURI.split(',')[1]);
    var array = [];
    for(var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], {type: 'image/png'});
}

var blob = dataURItoBlob(uri);
window.navigator.msSaveOrOpenBlob(blob, "my-image.png");
Chazt3n
fuente
0

Su problema esencialmente se reduce a "no todos los navegadores lo admitirán".

Podría probar una solución alternativa y servir los archivos descomprimidos de un objeto Flash, pero luego perdería la pureza de JS (de todos modos, no estoy seguro de si actualmente puede "arrastrar archivos al navegador" sin algún tipo de solución Flash) - ¿es esa una característica HTML5 tal vez?)

Piskvor salió del edificio
fuente