Это должно быть самое полное описание загрузки, которое вы когда-либо видели.

внешний интерфейс
Это должно быть самое полное описание загрузки, которое вы когда-либо видели.

предисловие

Некоторые демонстрации о загрузке и выгрузке, с которыми я столкнулся в некоторых проектах, которые я организовал, большая серия интерфейсов (то есть загрузка, выполненная на чистом интерфейсе + стороне узла, при условии, что работа по загрузке данных завершена) по внешнему интерфейсу), только немного, чтобы увидеть Официальную ссылку, не наступать на яму, подключи и играй, приветствуем вилку и звезду🌟, чтобы внести свой вклад в этот склад~ (PS лично думаю, что если вы не написали о загрузка и загрузка, это на самом деле довольно хлопотно, это может покрыть большинство сцен~)

Чистая фронтальная загрузка

  • на основе тега
  • location && iframe
  • FileSaver ---> [рекомендовать]

загрузка узла

  • Сначала скачайте на локалку, потом скачайте в браузер
  • Потоковая передача прямо в браузер для загрузки[рекомендовать]

frontend-download-sample, боюсь, что у всех не хватит терпения это прочитать, вот небольшая демо-картинка.

Загрузка и загрузка лично мне кажется, что фронтенд-разработка немного сложна, и вам нужно заниматься некоторыми дополнительными вещами вместо того, чтобы напрямую получать данные для рендеринга страницы, поэтому я подумал о том, чтобы разобраться и поделиться некоторыми сценами, с которыми я столкнулся. в обычное время Привет, не распыляйте ~ Я обычно связываюсь с проектом, чтобы загрузить несколько изображений, загрузить установочный пакет, загрузить изображение, загрузить установочный пакет и организовать данные для создания файла Excel для загрузки. Я еще не контактировал с другими типами, поэтому этот проект может иметь определенные ограничения, просто чтобы дать вам идею или план, любые другие идеи приветствуются в комментариях~

Чистая фронтальная форма загрузки

Как следует из названия, это чистая фронтенд-реализация, то есть она не зависит ни от какого бэкенда. Однако этот метод имеет определенные ограничения, такие как тип загрузки, метод записи, форма данных и так далее. Но так как это не зависит от бэкенда, то все равно настоятельно рекомендуется в допустимых пределах.В конце концов, это просто~

Скачать на основе тега

Если говорить о простоте, то это самое простое. это основано на<a>Способ загрузки файлов с тегами действительно очень прост. Способ применения следующий:

href: 文件的绝对/相对地址
download: 文件名(可省略,省略后浏览器自动识别源文件名)
<a href='xxx.jpg' download='file.jpg'>下载jpg图片</a>

Так как это так просто, должна быть проблема.

Изображение выше является официальной совместимостью, в настоящее время только FireFox и Chrome поддерживают атрибут загрузки. По крайней мере эти два незнакомы разработчикам, да и занимают они большой объем, так что ничего страшного, но потом я попробовал совместимость этих двух браузеров.

Вышеупомянутый является последней версией браузера FireFox.Вы можете видеть, что при нажатии на файл загрузки появится диалоговое окно, а затем щелкните файл сохранения для загрузки.В то же время, только те типы файлов, которые не могут быть открыты Браузер может загружать, например, изображения и текстовые файлы.

Это последняя версия Chrome, такая же, как FireFox.Для файлов изображений и текстовых файлов, которые могут быть открыты браузерами, они не будут загружены, в то время как файлы, такие как excel и установочные пакеты, могут быть загружены напрямую без каких-либо Любые вторичные операции подтверждения.

Так можно ли не позволять браузеру предварительно просматривать изображение (или файл pdf или txt)?

Конечно Почему? На самом деле, атрибут href тега a также может принимать другие формы URL в дополнение к относительным и абсолютным путям, такие как DataUrl и BlobUrl, которые мы будем использовать ниже. Пока используется эта форма, браузер может напрямую загружать изображение без предварительного просмотра, что, конечно, более проблематично в работе.

  • DataUrl
 // ./util.js
 // 图片转base64
 function image2base64(img) {  
  const canvas = document.createElement("canvas");  
  canvas.width = img.width;  
  canvas.height = img.height;  
  const ctx = canvas.getContext("2d");  
  ctx.drawImage(img, 0, 0, img.width, img.height);  
  const mime = img.src.substring(img.src.lastIndexOf(".")+1).toLowerCase();  
  const dataUrl = canvas.toDataURL("image/" + mime);  
  return dataUrl;
 }
 // html页面,将a标签href属性动态赋值为dataUrl
 <a id='downloadDataUrl' class="button is-dark">下载data:Url图片</a>
 ...
 <script>
  const image = new Image();
  image.setAttribute("crossOrigin",'Anonymous');
  image.src = '../files/test-download.png' + '?' + new Date().getTime();
  image.onload = function() {  
    const imageDataUrl = image2base64(image);  
    const downloadDataUrlDom = document.getElementById('downloadDataUrl');
    downloadDataUrlDom.setAttribute('href', imageDataUrl);
    downloadDataUrlDom.setAttribute('download', 'download-data-url.png');
    downloadDataUrlDom.addEventListener('click', () => {
      console.log('下载文件');
    });
  }  
</script>

Как показано на рисунке ниже, вы можете видеть, что это уже не файл предварительного просмотра, а прямая загрузка файла. Здесь есть некоторые ямы, такие какНекоторые проблемы и решения canvas.toDataUrl, больше говорить не буду, сами видите.

  • BlobUrl

Общая логика более сложная, первый файл -> base64 (dataUrl) -> blob -> blobUrl

 // 第一步:首先需要将文件转换成base64,方法上面一样
 // 第二步:将base64转换成blob数据
 // DataUrl 转 Blob数据
    function dataUrl2Blob(dataUrl) {
      var arr = dataUrl.split(','),
          mime = arr[0].match(/:(.*?);/)[1],
          bStr = atob(arr[1]),
          n = bStr.length,
          unit8Array = new Uint8Array(n);
      while (n--) {
        unit8Array[n] = bStr.charCodeAt(n);
      }
      return new Blob([unit8Array], { type: mime });
    } 
 // 第三步: 将blob数据转换成BlobUrl
 URL.createObjectURL(imageBlobData);
 
 // 完整代码
  <a id='downloadBlobUrl' class="button is-danger">下载blobUrl图片</a>
  ...
  const image2 = new Image();  
  image2.setAttribute("crossOrigin",'Anonymous');
  image2.src = '../files/test-download.png' + '?' + new Date().getTime();
  image2.onload = function() {  
    const imageDataUrl = image2base64(image2);
    const imageBlobData = dataUrl2Blob(imageDataUrl);
    const downloadDataUrlDom = document.getElementById('downloadBlobUrl');
    downloadDataUrlDom.setAttribute('href', URL.createObjectURL(imageBlobData));
    downloadDataUrlDom.setAttribute('download', 'download-data-url.png');
    downloadDataUrlDom.addEventListener('click', () => {
      console.log('下载文件');
    });
  }

【Резюме】: Chrome лучше по совместимости, но есть некоторые проблемы в обоих: вы не можете загружать изображения и текстовые файлы напрямую. При этом встречались и вышеописанные способы, dataUrl подходит для скачивания картинок, а blobUrl более хлопотный, но все равно очень полезен для скачивания текстовых файлов.Вы можете напрямую преобразовать загружаемый контент в данные BLOB-объектов, а затем преобразовать его в blobUrl для загрузки, подходящий для таких типов файлов, как .txt, .json и т. д..

Обновлено 29 августа 2021 г.Существует относительно стандартный вывод о том, просматривает ли браузер изображение или загружает изображение. Если это тот же исходный файл (изображение/txt), браузер будет напрямую следовать логике загрузки. Если это не тот же исходный файл, то, если браузер может его открыть, предварительный просмотр будет открыт непосредственно вместо логики загрузки. , Ниже приводится подробное введение в MDN.

  • Это свойство относится только кURL того же источника.
  • Хотя URL-адрес HTTP должен быть из того же источника, вы можете использоватьblob: URL и data: URL, чтобы пользователи могли загружать контент, созданный с помощью JavaScript (например, фотографии, созданные с помощью веб-приложения для рисования в Интернете).
  • Если заголовок HTTPContent-DispositionАтрибут назначает имя файла, отличное от этого атрибута, и атрибуты заголовка HTTP имеют приоритет над этим атрибутом.
  • Если атрибут заголовка HTTPContent-Dispositionустановлен как встроенный (т.е.Content-Disposition='inline'), то Firefox отдает приоритет заголовкам HTTPContent-Dispositionскачать свойство.

[Рекомендация]: если требования к загрузке относятся к особым типам файлов, таким как установочные пакеты, файлы Excel, и могут быть сохранены в другой доступной URL-ссылке в CDN. Что ж, этот способ идеален, конечно, если вы можете жить с проблемами совместимости, упомянутыми выше.В то же время, если вы используете dataUrl или blobUrl, потому что есть много проблем, таких как cors и тому подобное, рекомендуется использовать этот метод, но вам нужно сотрудничать с бэкэндом, то есть бэкэнд может вам помочь преобразовать его, вы можете напрямую взять преобразованный URL-адрес, чтобы загрузить его.

location.href и загрузка iframe

Приведенные выше два очень легко понять, то есть в другом окне или текущей адресной строке адрес указывает на ссылку для скачивания, а ссылка для скачивания требует dataUrl или blobUrl. Однако iframe является более продвинутым, то есть он может помочь нам добиться загрузок без flash.Как разработчик, каждый должен это понимать, поэтому у меня не так много ББ.

Из приведенной выше анимации видно, что этот метод на самом деле не так хорош, как<a>Загрузка тега, почему вы так говорите, потому что метод тега будет предварительно просматривать файлы, которые может просматривать браузер, но если вы правильно конвертируете его, вы все равно можете загрузить его. Однако независимо от того, является ли метод определения местоположения dataUrl или blobUrl, если это файл, который можно открыть во всех браузерах, например изображения, текстовые файлы и PDF-файлы, он даст вам предварительный просмотр напрямую, и только те файлы, которые браузеры делают не поддерживает предварительный просмотр может быть загружен. Так просто так.

Метод загрузки пакета iframe без флэш-памяти

Суть очень проста, то есть не дать текущему окну браузера выполнить операцию загрузки, а открыть другой iframe для загрузки файла. Но этот iframe невидим для пользователя~

Здесь следует отметить, что если это чистый интерфейс, рекомендуется не загружать файлы, которые могут быть открыты браузерами, такие как изображения, потому что вы не можете их увидеть, когда открываете их в скрытом iframe, то есть , его проблема по-прежнему выше. Вы можете скачать excel, zip и различные файлы ресурсов.

// 无闪现下载excel
function download(url) {
  const iframe = document.createElement('iframe');
  iframe.style.display = 'none';
  function iframeLoad() {
    console.log('iframe onload');
    const win = iframe.contentWindow;
    const doc = win.document;
    if (win.location.href === url) {
      if (doc.body.childNodes.length > 0) {
        // response is error
      }
      iframe.parentNode.removeChild(iframe);
    }
  }
  if ('onload' in iframe) {
    iframe.onload = iframeLoad;
  } else if (iframe.attachEvent) {
    iframe.attachEvent('onload', iframeLoad);
  } else {
    iframe.onreadystatechange = function onreadystatechange() {
      if (iframe.readyState === 'complete') {
        iframeLoad;
      }
    };
  }
  iframe.src = '';
  document.body.appendChild(iframe);

  setTimeout(function loadUrl() {
    iframe.contentWindow.location.href = url;
  }, 50);
}

Если вам нужна безфлэшевая загрузка в вашем проекте, ничего не делайте, просто позвонитеdownload(url), можно скачать без перепрошивки ~ доступно для личного тестирования

использоватьFileSaverМощный внешний плагин загрузки -> [настоятельно рекомендуется]

Метод загрузки FileSaver является полностью внешним (клиентским) методом загрузки.Он загружается на основе BLOB.Конечно, поскольку он основан на внешней загрузке, будут определенные ограничения на загрузку через браузер, т.е. , размер данных Blob не может быть слишком большим. , посмотрите соответствующие параметры, указанные на официальном сайте:

Видно, что в основном для поддерживаемых браузеров размер может достигать 500 МБ+, что должно удовлетворить большинство потребностей. Если файл действительно большой, официальный сайт дает альтернативуStreamSaver, я не изучал это, но поскольку рекомендация автора может быть очень хорошей, вы можете пойти и посмотреть, если вам интересно.

Как упоминалось ранее, FileSaver основан на Blob, что не соответствует действительности, вы можете посмотреть на официальном сайте:

Фактически, он поддерживает загрузку Blob, File и Url, но если он основан на URL-адресе, мне больше не нужно использовать FileSaver, что<a>Этикетки тоже хороши, не так ли? Потом на базе File он вообще используется в конкретных сценариях.Например при закачке будут использоваться такие API как FileReader.Честно говоря,я ​​ими особо не пользовался,и они все запакованы,поэтому вводить не буду их здесь.Я сказал это в начале, я надеюсь, что мои друзья смогут добавить что-то на этот склад, вы можете добавить свою загруженную демо здесь, очень приветствуем

Таким образом, загрузка, которую я обсуждаю в этой статье, основана на Blob. Первая задача — преобразовать файл в данные большого двоичного объекта. Все следующие примеры такие:

FileSaver ---- Скачать холст

зависит от -canvas-to-blob

Если эта демонстрация проста, вы можете напрямую использовать холст, чтобы нарисовать изображение на странице, а затем загрузить его, но лучше загрузить изображение напрямую, так что это более хлопотно, написать белую доску на холсте, а затем загрузить содержимое мы нарисовали и назвали его для загрузки.

 // 生成下载的文件名 
 function generateFilename(id, mime) {
    const filename = document.getElementById(id).value || document.getElementById(id).placeholder;
    return filename + mime;
  }
  const canvasDownloadDom = document.getElementById('download-canvas');
  canvasDownloadDom.addEventListener('click', () => {
    const canvas = document.getElementById('canvas');
    const filename = generateFilename('canvasName', '.png');
    if (canvas.toBlob) {
      // 调用方法将canvas转换成blob数据
      canvas.toBlob(
          function (blob) {
            // 调用FileSaver方法下载
            saveAs(blob, filename);
          },
          'image/png'
      );
    }   
  });

Код очень прост, и заинтересованные партнеры могут посмотреть код внутри каждого плагина. У меня есть пример на уровне приложения.

FileSaver ---- Загрузка изображений напрямую

Прямая загрузка изображения заключается в преобразовании изображения в данные BLOB-объекта, а затем в его загрузке.

// FileSaver 下载文件
  const image = new Image();  
  image.setAttribute("crossOrigin",'Anonymous');
  image.src = '../files/test-download.png' + '?' + new Date().getTime();
  image.onload = function() {  
    const imageDataUrl = image2base64(image);
    const imageBlobData = dataUrl2Blob(imageDataUrl);
    const downloadImageDom = document.getElementById('download-image');
    downloadImageDom.addEventListener('click', () => {
      saveAs(imageBlobData, 'test-download.png');
    });
  }

Этот код еще проще, это передний<a>Код для тега для загрузки данных Blob, преобразование данных такое же, но для загрузки используется FileSaver.

FileSaver - загрузка текстовых файлов

Загрузка текстовых файлов стала еще проще, поскольку JavaScript поддерживает прямое преобразование строк в объекты Blob.

const textBlob = new Blob(["your target string"], {type: "text/plain;charset=utf-8"});

Загруженный текстовый файл выглядит следующим образом:

 // FileSaver 下载文本文件
  const txtDownloadDom = document.getElementById('download-txt');
  txtDownloadDom.addEventListener('click', () => {
    const textarea = document.getElementById('textarea');
    const filename = generateFilename('textareaName', '.txt');
    const textBlob = new Blob([textarea.value], {type: "text/plain;charset=utf-8"});
    saveAs(textBlob, filename);
  });

FileSaver - Загрузка файлов Excel (сjs-xlsx)

Предыдущие относительно просты, но по сути, кроме загрузки картинок, там может и не быть никаких бизнес-сценариев, которые нужно делать в обычное время. Следующее, что нужно сказать, это то, что почти все бизнес-системы могут столкнуться, то есть - скачать отчеты, то есть файлы Excel. Здесь FileSaver используется с js-xlsx для выполнения чистой внешней загрузки Excel~

Загруженный файл выглядит так:

// 下载excel文件
  const excelDownloadDom = document.getElementById('download-excel');
  excelDownloadDom.addEventListener('click', () => {
    // 找到table节点调用方法转化数据
    const wb = XLSX.utils.table_to_book(document.querySelector('#table-excel'));
    // 生成excel数据
    const wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' });
    try {
      // 下载excel文件
      saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'table-excel.xlsx');
    } catch (e) {
      if (typeof console !== 'undefined') console.log(e, wbout)
    }
  });

Здесь я просто расскажу, как использовать FileSaver для загрузки файлов Excel в интерфейсе.js-xlsxКак преобразовать данные в Excel здесь не будет. я просто звонюjs-xlsxСпособ преобразования таблицы в excel,js-xlsxЕсть также много расширенных функций, если у вас есть это требование, перейдите к официальной документации.js-xlsxЭто хорошо~

Сторона узла с загрузкой (большой интерфейс)

Загрузка с поддержкой back-end намного проще, почему, ведь все вышеперечисленные чистые front-end загрузки могут использоваться в связке с back-end, то есть back-end генерирует соответствующую ссылку для скачивания для загрузки данных и возвращает его в интерфейс, и интерфейс нажимает кнопку. Вам нужно использовать вышеуказанные методы для загрузки, и вы обязательно сможете успешно загрузить.
Затем сторона узла должна загрузить что-то другое с загрузкой, то естьфайловый поток.

Существует множество сценариев, когда большие файлы не существуют в CDN, а хранятся в памяти в виде файловых потоков. Тогда соответствующей ссылки для скачивания нет.Когда соответствующий файл скачивается, бэкенд возвращает файловый поток. И node предоставляет намStreamПоддерживаются различные манипуляции с потоком. Таким образом, мы можем загружать файлы прямо на стороне узла.

Сначала скачайте на локалку, а потом скачайте из браузера

  • фс скачать эксель

Загруженный файл Excel:

// 第一步:构造数据
const data = [
  [1, 2, 3],
  [true, false, null, 'sheetjs'],
  ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'],
  ['baz', null, 'qux'],
];
// 第二步:生成excel的Buffer数据
const buffer = xlsx.build([{ name: 'mySheetName', data }]);

// 第三步:写文件到本地
const tmpExcel = `filename.xlsx`;

fs.writeFileSync(
  tmpExcel,
  buffer,
  {
    encoding: 'utf8',
  },
  err => {
    if (err) throw new Error(err);
  },
);
// 第四步:从本地读取文件下载到浏览器
res.setHeader('Content-disposition', `attachment; filename="${tmpExcel}"`);
res.setHeader('Content-Type', 'application/octet-stream');
// pipe generated file to the response
fs.createReadStream(tmpExcel).pipe(res);
// 下载完成后删除文件
fs.unlinkSync(tmpExcel);

Загрузите excel на стороне узла, который я не используюjs-xlsxноnode-xlsx, поскольку он очень прост в создании данных и имеет мощные функции, всем настоятельно рекомендуется его использовать~

  • скачать файл фс

Сцену здесь описать не просто, потому что я помещаю файлы в локальный каталог для демонстрации, поэтому я читаю локальные файлы, загружаю их локально, а затем загружаю в браузер.Я болен? . . Общий сценарий таков, что файл сохраняется в памяти в виде файлового потока, а затем мы загружаем его в локалку через интерфейс, а затем загружаем из локального в браузер. Или загрузите файл и сохраните его локально, а затем выполните соответствующие операции локально.Я не буду писать пример кода здесь.

Сторона узла напрямую переходит в браузер для загрузки [рекомендуется]

На стороне узла я использую экспресс-фреймворк (остальные фреймворки такие же), если вы заходите напрямую из файлового потока, то звоните напрямуюres.attachment()Загрузите файловый поток, если это путь к файлу, то вы можете напрямуюres.download(filepath). Подробности смотрите в демо

  • Загрузите Excel напрямую

На самом деле вышеописанный процесс прошел еще один этап, почему? Потому что после получения буфера мы можем напрямую передать буфер в браузер для загрузки. Здесь я использую инфраструктуру Express, которая используется напрямую.res.attachment()метод подойдет.Скачанный файл точно такой же, как и выше, и я не буду его показывать.

Насколько я понимаю, второй явно лучше первого, зачем указывать первый? Я лично считаю, что, хотя первый метод определенно принесет в жертву определенную производительность, можно выполнить некоторую проверку файла после его локальной загрузки, например, является ли файл полным, является ли имя файла допустимым, а иногда и сцена возможный. В конце концов, не все сценарии загрузки так же просты, как Демо. Существование разумно, поэтому он все еще указан.

// 第一步:构造数据
const data = [
  [1, 2, 3],
  [true, false, null, 'sheetjs'],
  ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'],
  ['baz', null, 'qux'],
];
// 第二步:生成buffer
const buffer = xlsx.build([{ name: 'mySheetName', data }]);
// 第三步:直接下载
res.status(200)
  .attachment('bufferExcel.xlsx')
  .send(buffer);
// 上面下载代码等同于下面这段代码(nodejs原生代码)
res.setHeader('Content-disposition', `attachment; filename="${tmpExcel}"`);
res.setHeader('Content-Type', 'application/octet-stream');
res.end(buffer);
  • Файловый поток прямой загрузки

Здесь я помещаю пакет установки файла локально, а затем сначала читаю содержимое файла и загружаю его в браузер~

// 第一种,已知文件路径直接下载
try {
  const packagePath = 'static/download/iTerm2-3_2_5.zip';
  res.download(path.join(rootDir, packagePath));
} catch (e) {
  console.error(e);
}
// 第二种,读取本地文件流向浏览器
res.setHeader('Content-disposition', `attachment; filename="download-package.zip"`);
res.setHeader('Content-Type', 'application/octet-stream');
fs.createReadStream(path.join(rootDir, packagePath), 'utf-8').pipe(res);

request

Наконец, я дам вам библиотеку запросов Http (Https), которая использует Stream API до крайности — запрос.

// 不加这一行下载下来的文件没有后缀
res.setHeader('Content-disposition', 'attachment; filename=node-v8.14.0-linux-x64.tar.gz');
request('https://npm.taobao.org/mirrors/node/v8.14.0/node-v8.14.0-linux-x64.tar.gz')
  .pipe(res);

Здесь, в целях экономии времени, я использовал строительные леса, которые соорудил ранее.Next-Antd-Scafflod, Демо написано прямо здесь. Вы можете понять, что я рекламирую, я не против, если вы кликните и поставите звезду 😄.

Суммировать

Я очень благодарен видеть здесь, несмотря ни на что, резюме не очень хорошее, его можно понять как статью для самостоятельного резюме. Было бы еще лучше, если бы это могло вас немного вдохновить. Наконец, если вы заинтересованы или у вас есть вопросы, вы можете оставить сообщение или перейти непосредственно на склад, чтобы упомянуть ~

Звезда🌟Адрес:frontend-download-sample