开发日常——下载弹窗闪退
记录一下前几天遇到的一个问题,用户在点击下载时,前端会发起一个请求,后端返回下载链接。
响应格式可能是这样的,前端要做的处理也很简单,只需要window.open(res.data)即可触发下载。
{
"status": 0,
"success": true,
"message": "SUCCESS",
"data": "http://xxx.xxx.com/xxx.exe"
}
问题出现在前不久,线上的dev环境在window.open的时候突然打开一个窗口没有触发下载就闪退了,验证返回的下载链接是有效的,诡异的是在本地开发环境下是可以直接下载的。
控制台并没有任何报错,怀疑可能是window.open被浏览器阻止了,于是使用了a标签下载,未果。又尝试使用了一个download的工具函数如下:
/**
* 获取 blob
* @param {String} url 目标文件地址
* @return {Promise}
*/
function getBlob(url: string) {
return new Promise<Blob>((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.response);
}
};
xhr.onerror = () => {
reject('getBlob error');
};
xhr.send();
});
}
/**
* 保存
* @param {Blob} blob
* @param {String} filename 想要保存的文件名称
*/
export function saveAs(blob: Blob, filename: string) {
// @ts-ignore msSaveOrOpenBlob
if (window.navigator.msSaveOrOpenBlob) {
// @ts-ignore msSaveBlob
navigator.msSaveBlob(blob, filename);
} else {
const link = document.createElement('a');
const body = document.querySelector('body');
link.href = window.URL.createObjectURL(blob);
link.download = filename;
// fix Firefox
link.style.display = 'none';
// @ts-ignore
body.appendChild(link);
link.click();
// @ts-ignore
body.removeChild(link);
window.URL.revokeObjectURL(link.href);
}
}
/**
* 下载
* @param {String} url 目标文件地址
* @param {String} filename 想要保存的文件名称
* @param {Function} fallback 下载失败回调
*/
export default function download(url: string, filename: string, fallback?: () => void) {
getBlob(url)
.then((blob) => {
saveAs(blob, filename);
})
.catch(() => {
if (fallback && typeof fallback === 'function') {
fallback();
}
});
}
终于!在控制台看到了报错。(之后尝试了一下location.href也是可以看到报错的)
原因是在线上域名是https开头,直接去打开一个http的下载链接会触发浏览器的拦截,而本地开发是http开头的可以直接下载,让后端返回一个https开头的链接即可。