Загрузка файла на фронте – простая задача. Обычно она заключается в создании тега a
и добавлением в него атрибута href
. Иногда имеет смысл добавить еще и атрибут download
, чтобы файл при этом не открывался в браузере. Но бывают такие случаи, когда загрузка файла таким образом невозможна.

Самый просто пример – для загрузки файла нужно указать дополнительные http заголовки. Или когда нужно следить за процессом загрузки файла и выводить это внутри gui. А может быть вы хотите вывести сообщение об успешной загрузке или сделать обработку ошибок? В таком случае может помочь загрузка файла через ajax
Для начала напишем функцию, которая собирает эмулирует загрузку файла из blob
.
function downloadFileFromBlob(blob, fileName) {
// Создаём ссылку на blob
const urlFile = URL.createObjectURL(blob);
// Создаём фейковый элемент <a>
const element = document.createElement('a');
// Формируем минимальные необходимые атрибуты
element.setAttribute('href', urlFile);
element.setAttribute('download', fileName);
// Эмулируем нажатие на элемент
element.dispatchEvent(new MouseEvent('click'));
}
При запуске этой функции происходит эмуляция загрузки файла. Но так как по сути файл загружается с диска, загрузка происходит почти мгновенно. Примерно такой же эффект можно наблюдать при загрузке файлов с mega.nz
Напишем функцию, которая получает это самый blob
из сети. Разберем на примере файла первого выпавшего мне в гугле файла по запросу "example pdf file for download".
const examplePdfLink = 'http://www.africau.edu/images/default/sample.pdf';
fetch(examplePdfLink)
.then(res => {
// На этом этапе можно посмотреть на статус http
// и вывести какие-нибудь сообщения в gui
return res.blob();
})
.then(blobRes => {
// Вызываем ранее написанную функцию
downloadFileFromBlob(blobRes, 'test.pdf');
})
.catch(console.error)
Вместо fetch
можно использовать axios
const examplePdfLink = 'http://www.africau.edu/images/default/sample.pdf';
const response = await axios.get(examplePdfLink, {
// Явно укажем формат, в котором мы ждём ответ
responseType: 'blob'
});
if (response.status === 200) {
downloadFileFromBlob(response.data, 'example.pdf');
}
Так же axios предоставляет удобный интерфейс для отслеживания прогресса загрузки. Подробнее про это можно прочитать в документации. Выведем в качестве примера процент загрузки в консоль.
// Возьмём в качестве примера файл размером в 100Мб
const examplePdfLink = 'https://speed.hetzner.de/100MB.bin';
const response = await axios.get(examplePdfLink, {
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
console.log(
`${(progressEvent.loaded / progressEvent.total * 100).toFixed(2)}%`
);
}
})
if (response.status === 200) {
downloadFileFromBlob(response.data, 'example.pdf');
}
Для реализации этого можно использовать и библиотеки. Например, js-file-download или FileSaver.js. Моя же цель была показать, как это примерно работает под капотом.