|
|
|
|
@ -184,15 +184,79 @@ export function formatFileSize(size) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将资源地址转成当前页面协议下的同源路径,避免 HTTPS 页面下载被 302 到 HTTP 后触发 Mixed Content。
|
|
|
|
|
*/
|
|
|
|
|
export function toSameOriginUrl(url) {
|
|
|
|
|
if (!url || typeof url !== "string") {
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
const parsed = new URL(url, window.location.origin);
|
|
|
|
|
if (parsed.hostname === window.location.hostname) {
|
|
|
|
|
return parsed.pathname + parsed.search + parsed.hash;
|
|
|
|
|
}
|
|
|
|
|
if (window.location.protocol === "https:" && parsed.protocol === "http:") {
|
|
|
|
|
parsed.protocol = "https:";
|
|
|
|
|
return parsed.toString();
|
|
|
|
|
}
|
|
|
|
|
return parsed.toString();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (window.location.protocol === "https:") {
|
|
|
|
|
return url.replace(/^http:\/\//i, "https://");
|
|
|
|
|
}
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function download(url) {
|
|
|
|
|
var downloadLink = document.createElement("a");
|
|
|
|
|
downloadLink.href = url;
|
|
|
|
|
// 将下载链接添加到页面并模拟点击下载
|
|
|
|
|
document.body.appendChild(downloadLink);
|
|
|
|
|
downloadLink.click();
|
|
|
|
|
|
|
|
|
|
// 清理下载链接
|
|
|
|
|
document.body.removeChild(downloadLink);
|
|
|
|
|
if (!url) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const finalUrl = toSameOriginUrl(url);
|
|
|
|
|
const filename = decodeURIComponent(
|
|
|
|
|
(String(finalUrl).split("?")[0].split("/").pop()) || "download"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const trigger = (href, downloadName) => {
|
|
|
|
|
const downloadLink = document.createElement("a");
|
|
|
|
|
downloadLink.href = href;
|
|
|
|
|
if (downloadName) {
|
|
|
|
|
downloadLink.setAttribute("download", downloadName);
|
|
|
|
|
}
|
|
|
|
|
document.body.appendChild(downloadLink);
|
|
|
|
|
downloadLink.click();
|
|
|
|
|
document.body.removeChild(downloadLink);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 同源文件走 blob 下载,不跟随 http 跳转,避免 Mixed Content 拦截。
|
|
|
|
|
if (typeof finalUrl === "string" && finalUrl.startsWith("/")) {
|
|
|
|
|
fetch(finalUrl, { credentials: "same-origin", redirect: "follow" })
|
|
|
|
|
.then((res) => {
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
throw new Error("download failed");
|
|
|
|
|
}
|
|
|
|
|
const responseUrl = res.url || "";
|
|
|
|
|
if (
|
|
|
|
|
window.location.protocol === "https:" &&
|
|
|
|
|
/^http:\/\//i.test(responseUrl)
|
|
|
|
|
) {
|
|
|
|
|
throw new Error("insecure redirect");
|
|
|
|
|
}
|
|
|
|
|
return res.blob();
|
|
|
|
|
})
|
|
|
|
|
.then((blob) => {
|
|
|
|
|
const blobURL = window.URL.createObjectURL(blob);
|
|
|
|
|
trigger(blobURL, filename);
|
|
|
|
|
window.URL.revokeObjectURL(blobURL);
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {
|
|
|
|
|
trigger(finalUrl, filename);
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trigger(finalUrl, filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function paramsSerializer(params) {
|
|
|
|
|
|