Загрузка binary-файла
Возникла задача ― загрузить с сервера XLSX-файл. Запрос ― POST. Файл, понятное дело, бинарный. На проекте уже подключена jQuery, и, первым делом, я решил воспользоваться её стандартным $.ajax. Сколько не бился ― так и не удалось получить blob-результат от запроса. Использовать же решение через iframe-ы и form-ы тоже не хотелось. Во-первых уж больно костыльно (привет 90-ые). во-вторых нужно будет ещё чудить с передачей параметров POST-запроса (content-type: json). Гуглил-гуглил, но ни одного вменяемого решения (которое не стыдно было бы утащить в проект) я так и не нашёл. Но, т.к. интересует поддержка только последних версий современных браузеров, удалось найти и применить более изящное и функциональное решение. Итак…
- Забудем про jQuery и воспользуемся нативным XMLHttpRequest-ом
- Указав ему responseType = 'blob'.
- Получившийся результат (blob) загоняем в URL.createObjectURL.
- В результате получим псевдо-URL ссылку, начинающуюся с "blob:".
Ну а дальше уже по-желанию. Я генерирую новый <a/>-тег, задаю ему нужные аттрибуты download и href (та самая blob-ссылка), вызываю у ссылки .click(). Апосля ссылку удаляю. Проверял в Firefox-е и Chrome-е.
Небольшая заготовка:
function loadBlob(params, data)
{
return new Promise((resolve, reject) =>
{
const xhr = _.assign(new XMLHttpRequest(),
{
onload(){ resolve(xhr.response); },
onerror(e){ reject(e.target.status); }
});
xhr.open(params.method || 'POST', params.url);
xhr.responseType = 'blob';
const contentType = params.contentType || 'application/json';
xhr.setRequestHeader('content-type', contentType);
if(contentType === 'application/json')
data = JSON.stringify(data);
xhr.send(data);
});
}
Ну и загрузка файла:
downloadBlob(blob, fname)
{
const url = window.URL || window.webkitURL;
const object = url.createObjectURL(blob);
var $a = $('<a>',
{
'href': object,
'download': _.isString(fname) ? fname : 'file.txt'
})
.appendTo(document.body);
$a[0].click();
$a.remove();
}