Como contornar a restrição do navegador e anexar dois ou mais arquivos de uma vez: anexo de vários arquivos

Olá, Habr!



Vamos resolver um problema não trivial. Imagine que você precise baixar os dados pela interface de forma elementar, por exemplo, clicar no botão "Baixar arquivos".



Vamos pegar o Chrome v.88 padrão. A tarefa soa assim:



  • Gere arquivos do lado do cliente.
  • Baixe todos os arquivos gerados com um clique.


Pode ser qualquer coisa: um monte de binários, grandes arquivos com backups, uma galeria de fotos e assim por diante. Falaremos especificamente sobre o mecanismo de download como tal, por isso tomaremos o download de texto e imagens como exemplo.





Claro, você pode resolver esse problema simplesmente compactando todos os arquivos necessários em um arquivo ZIP e, em seguida, baixando-o. Acontece que o usuário baixa um único arquivo, que ele então descompacta sozinho. Por exemplo, você pode usar a biblioteca jszip , que permite baixar um conjunto de arquivos compactando-os.



Aqui está um pequeno exemplo de download pré-compactado dos documentos:



var zip = new JSZip();
zip.file("Hello.txt", "Hello World\n");
var img = zip.folder("images");
img.file("smile.gif", imgData, {base64: true}); zip.generateAsync({type:"blob"}).then(function(content) {
// see FileSaver.js
saveAs(content, "example.zip"); });
      
      





"Onde está a não trivialidade aqui?" - você pergunta. E você estará certo. E se estamos falando de download simultâneo de dois, três ou dez arquivos do site? Por exemplo: existe uma lista no select, onde você pode selecionar um determinado número de arquivos para baixar. Vamos introduzir uma condição adicional: o usuário não possui um arquivador instalado, então descartamos a opção de compactação para o arquivo. Como resolver este problema?



Primeiro, vamos preparar o navegador. O Chrome proíbe o download de vários arquivos por padrão. Isto é por razões de segurança. Portanto, esta função deve primeiro ser desbloqueada nas configurações do navegador:



  1. Vamos para as configurações do site: chrome: // settings / content.
  2. Vá para Permissões adicionais.
  3. Escolha downloads automáticos.
  4. Adicione o site necessário à categoria Permitir.








Ótimo, agora seu navegador se tornou menos seguro e permite que você baixe vários arquivos em um determinado site ao mesmo tempo.



Abordagem nº 1 - FileReader



Vejamos a primeira abordagem usando o exemplo de geração de arquivos usando FileReader e a API de leitura base64. Noto imediatamente que FileReader tem uma API bastante extensa, então escolha o que você mais gosta: text, arrayBuffer ou binaryString.



(function () {
  const button = document.getElementById("download_with_reader");
  const content = ["content-1", "content-2", "content-3"];
    const createLink = () => {
    let link = document.createElement('a');
    link.download = 'hello.txt';
    return link;
  }
    const generateBlob = () => {
    for (const [index, value] of content.entries()) {
      const blob = new Blob([value], { type: "text/plain" });
      download(blob, index);
    }
  }
  const download = (blob, index) => {
    const link = createLink();
    let reader = new FileReader();
    reader.readAsDataURL(blob);
    reader.onload = function () {
      link.href = reader.result;
      link.download = `content-${index+1}.txt`;
      link.click();
    }
  }
    button.addEventListener("click", generateBlob);
}) ();

      
      





[código no Gitlab]



Abordagem # 2 - createObjectURL



Você também pode usar createObjectURL - permite armazenar objetos File ou Blobs.



(function () {
  const button = document.getElementById("download_with_url_object");
  const content = ["content-1", "content-2", "content-3"];
  
  const createLink = () => {
    let link = document.createElement('a');
    link.download = 'hello.txt';
    return link;
  }
  const generateBlob = () => {
    for (const [index, value] of content.entries()) {
      const blob = new Blob([value], { type: "text/plain" });
      download(blob, index);
    }
  }
  const download = (blob, index) => {
    const link = createLink();
    link.href = URL.createObjectURL(blob);
    link.download = `content-${index+1}.txt`;
    link.click();
    URL.revokeObjectURL(link.href);
  }
   button.addEventListener("click", generateBlob);
}) ();

      
      





[código no Gitlab]



Abordagem nº 3 - Baixar do URL



As duas opções acima geram arquivos do lado do cliente. Claro, nem sempre será o caso, de vez em quando recebemos arquivos do back-end por meio de links diretos. Isso pode ser feito baixando de um URL. O Chrome requer latência, portanto, a implementação de latência artificial se tornará um recurso desse método.



(function () {
(function () {
  const button = document.getElementById("download_with_request");
  const urls = ["images/image-1.jpg", "images/image-2.jpg", "images/image-3.jpg"];
  
  const delay = () => new Promise(resolve => setTimeout(resolve, 1000));
  
  const downloadWithRequest = async () => {
    for await (const [index, url] of urls.entries()) {
      await delay();
      const link = document.createElement("a");
      link.href = url;
      link.download = `image-${index+1}`;
      link.click();
    }
  }
  
  button.addEventListener("click", downloadWithRequest);
}) ();


      
      





[código no Gitlab]



Total



Aqui estão três maneiras bastante simples de baixar vários arquivos de um site ao mesmo tempo e fazer isso rapidamente. O principal é ativar as permissões necessárias para um site específico e, em seguida, escolher o método de sua preferência.



All Articles