предисловие
В проекте мы часто сталкиваемся с необходимостью загрузки или экспорта ресурсов на стороне сервера, которые обычно делятся на два подхода.
- Получите файловый поток, закодируйте его и скачайте
- Получите URL-адрес файла и загрузите его напрямую
В этой статье в основном обсуждается второй метод, и в конце будет упомянут метод файлового потока.
Политика безопасности браузера
Прежде чем внедрять этот метод, нам нужно знать некоторые механизмы безопасности браузера, чтобы вредоносный код не нанес вред пользователям.
Современные браузеры (кроме ie8) обнаруживают новые окна, сгенерированные прямыми непользовательскими операциями, и обычно блокируют их, например, открытие новых окон в обратных вызовах ajax, потому что эти операции не находятся в потоке, по которому щелкнул пользователь, поэтому они будут заблокированы.
Предварительно открыть новую вкладку
упражняться
- Откройте новую вкладку перед асинхронной операцией
- Адрес бэкэнд-ресурса запроса
- После получения URL-адреса измените URL-адрес пустой страницы.
const downloadTab = window.open('about:blank');
ajax.get('xxx').then(url => {
// 使用后端资源的url进行下载
downloadTab.location.href = href;
}).catch(err => {
// 处理异常
downloadTab.close();
})
недостаток
- Будет ли запрос выполнен успешно или нет, будет мигать новая страница
- Когда открывается новая страница, это проблема, потому что, если время запроса слишком велико, пользователь может закрыть новую страницу сам, и еще сложнее справиться с тем, когда страница запускает загрузку, потому что если вы просто измените url и закройте окно, возможно, его еще нет. Запустите операцию загрузки.
создать iframe
упражняться
Чтобы избежать проблемы мерцания страницы и времени закрытия, вы можете использовать метод динамического создания iframe на текущей странице для прямой загрузки.
ajax.get('xxx').then(href => {
if (!href) {
return;
}
if (!this.downIframe) {
this.downIframe = document.createElement('iframe'); // 动态创建iframe
this.downIframe.src = href; // iframe 中加载的页面
this.downIframe.id = 'downloadIframe'; // iframe 中加载的页面
this.downIframe.style.width = '1px';
this.downIframe.style.height = '1px';
this.downIframe.style.position = 'absolute';
this.downIframe.style.left = '-100px';
document.body.appendChild(this.downIframe); // 添加到当前窗体
} else {
this.downIframe.src = href; // iframe 中加载的页面
}
}).catch(err => {
// 处理异常
})
недостаток
Хотя файл можно скачать элегантно, но будет головной болью, если вам нужно настроить имя загружаемого файла.Нам нужно время, чтобы изменить имя загруженного файла, иначе это будет имя файла сервера.
Создание ярлыков
Используйте свойство загрузки, чтобы установить имя файла,
ajax.get('xxx').then(href => {
if (!href) {
return;
}
var a = document.createElement('a');
var url = href;
var filename = 'test.zip';
a.href = url;
a.download = filename; // 在没有download属性的情况,target="_blank",仍会阻止打开
a.click();
}).catch(err => {
// 处理异常
})
Уведомление:
Некоторые браузеры требуют, чтобы тег a был встроен в страницу для выполнения.
поток файлов обработки
Наконец, поговорим о том, что делать, если бэкенд возвращает поток.
function funDownload(content, filename) {
// 创建隐藏的可下载链接
var link = document.createElement('a');
link.download = filename;
link.style.display = 'none';
// 字符内容转变成blob地址
var blob = new Blob([content]);
//如果是excel格式
//var blob = new Blob([content], {type: 'application/vnd.ms-excel'}),
link.href = URL.createObjectURL(blob);
// 触发点击
document.body.appendChild(link);
link.click();
// 然后移除
document.body.removeChild(link);
};
URL.createObjectURL() Статический метод создаетDOMString, который содержит URL-адрес, представляющий объект, указанный в параметре. время жизни этого URL и окно, в котором он был созданdocumentсвязывать. Этот новый объект URL представляет указанныйFileобъект илиBlobобъект.
Уведомление:
при каждом звонке
createObjectURL()
создается новый объект URL, даже если вы уже создали его с тем же объектом в качестве параметра. Когда эти объекты URL больше не нужны, каждый объект должен бытьURL.revokeObjectURL()метод освобождения. Браузер автоматически освобождает их при выходе из документа, но для оптимальной производительности и использования памяти вы должны активно освобождать их, когда это безопасно.