Skip to content

Как скачать файл из запроса?

Задача: кинуть http-запрос, который отдает бинарный файл (напр. эксель), и скачать его в браузере

  1. Кидаем запрос:

    const resp = await fetch(...);
    
  2. Нам нужен Blob и content-disposition-хедер:

    const contentDispositionHeader = resp.headers.get("content-disposition");
    const blob = await resp.blob();
    
  3. Далее парсим хедер - достаем filename

    function parseContentDisposition(disposition): string | undefined {
        if (disposition && disposition.indexOf('attachment') !== -1) {
            var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
            var matches = filenameRegex.exec(disposition);
            if (matches != null && matches[1]) {
                return matches[1].replace(/['"]/g, '');
            }
        }
    }
    
    const fileName = decodeURIComponent(parseContentDisposition(contentDispositionHeader));
    
  4. И качаем Blob с названием filename, создавая <a href download>

    const downloadBlob = (blob, fileName) => {
        const url = window.URL.createObjectURL(new Blob([blob]));
        const link = document.createElement('a');
        link.href = url;
        link.setAttribute('download', fileName);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    };
    
    downloadBlob(blob, fileName);
    

Полный код:

function parseContentDisposition(disposition): string | undefined {
    if (disposition && disposition.indexOf('attachment') !== -1) {
        var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        var matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) {
            return matches[1].replace(/['"]/g, '');
        }
    }
}

const downloadBlob = (blob, fileName) => {
    const url = window.URL.createObjectURL(new Blob([blob]));
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', fileName);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
};

const resp = await fetch(...);

const contentDispositionHeader = resp.headers.get("content-disposition");
const blob = await resp.blob();

const fileName = decodeURIComponent(parseContentDisposition(contentDispositionHeader));

downloadBlob(blob, fileName);