diff --git a/src/utils/index.js b/src/utils/index.js index c27aaee..11af345 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -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) { diff --git a/src/views/MiddleSchoolIndicator/MiddleSchoolIndicator.vue b/src/views/MiddleSchoolIndicator/MiddleSchoolIndicator.vue index 1e1c51f..078f808 100644 --- a/src/views/MiddleSchoolIndicator/MiddleSchoolIndicator.vue +++ b/src/views/MiddleSchoolIndicator/MiddleSchoolIndicator.vue @@ -23,6 +23,21 @@ >新增