From bf20a0c1445607e3a6fa1852c2d246c7aaab999d Mon Sep 17 00:00:00 2001 From: lion <120344285@qq.com> Date: Wed, 16 Sep 2026 15:10:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=A6=E6=A0=A1=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/index.js | 80 +++++++++++++++++-- .../MiddleSchoolIndicator.vue | 20 ++++- .../components/AddMiddleSchoolIndicator.vue | 1 + 3 files changed, 92 insertions(+), 9 deletions(-) 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 @@ >新增