From f58d449e2c1aaba4507055b3b8c7a7651ad3f1e7 Mon Sep 17 00:00:00 2001 From: TongTongStudio Date: Sun, 9 Aug 2026 12:40:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(app-manager):=20=E4=BC=98=E5=8C=96=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E6=96=87=E4=BB=B6=E5=89=8D=E7=9A=84=E8=B5=84=E6=BA=90?= =?UTF-8?q?=E6=9C=89=E6=95=88=E6=80=A7=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 防止将后端返回的 HTML/JSON 错误页面当作安装包下载,同时兼容 CORS 限制场景下的降级下载 --- .../app-manager/upload-package/index.vue | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/views/app-manager/upload-package/index.vue b/src/views/app-manager/upload-package/index.vue index 119d19a4..70dddd97 100644 --- a/src/views/app-manager/upload-package/index.vue +++ b/src/views/app-manager/upload-package/index.vue @@ -341,15 +341,39 @@ function openDetail(item: AppPackage) { detailVisible.value = true; } -function download(item: AppPackage) { +async function download(item: AppPackage) { if (!item.fileUrl) { ElMessage.warning("文件地址缺失"); return; } + + const url = withBase(item.fileUrl); + const fileName = item.originalName || `${item.packageName}.${item.packageType}`; + + // 先校验资源是否真实存在,避免后端返回的错误页(如 f.txt)被当作文件下载。 + // 受 CORS 限制时 HEAD 可能失败,此时回退为直接下载( 下载不受 CORS 限制),避免误报。 + try { + const resp = await fetch(url, { method: "HEAD" }); + if (!resp.ok) { + ElMessage.error(`下载失败:资源不存在(${resp.status})`); + return; + } + const contentType = resp.headers.get("Content-Type") || ""; + // 资源存在但返回的是文本/HTML/JSON 错误页,而不是实际安装包 + if (/(text\/html|text\/plain|application\/json)/i.test(contentType)) { + ElMessage.error("下载失败:资源未找到或链接无效"); + return; + } + } catch { + // HEAD 不可达(多为跨域限制),直接走原生下载兜底 + } + const a = document.createElement("a"); - a.href = withBase(item.fileUrl); - a.download = item.originalName || `${item.packageName}.${item.packageType}`; + a.href = url; + a.download = fileName; + document.body.appendChild(a); a.click(); + document.body.removeChild(a); } async function handleDelete(item: AppPackage) {