From e0e6c50b89c71510f497cf7d9e95f0832fb02ec3 Mon Sep 17 00:00:00 2001 From: xiyidaiwa Date: Tue, 11 Aug 2026 18:44:32 +0800 Subject: [PATCH] =?UTF-8?q?fix(cache):=20=E5=88=97=E8=A1=A8/=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E8=AF=B7=E6=B1=82=E7=A6=81=E7=94=A8=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E7=BC=93=E5=AD=98=EF=BC=8C=E6=A0=B9=E6=B2=BB=E6=96=B0?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E4=B8=8A=E6=9E=B6=E5=90=8E=E6=90=9C=E4=B8=8D?= =?UTF-8?q?=E5=88=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C1: 主进程 onBeforeSendHeaders 对 .json 数据请求注入 Cache-Control: no-cache + Pragma - C2: 渲染端 axiosInstance 与 priorityConfigAxios 对 .json GET 追加 ?_t 时间戳版本戳,穿透 CDN 边缘缓存 - 按去除 query 的 pathname 判断 .json,兼容 C2 自身追加的 ?_t,避免 C1/C2 交互失效 - 根因: nginx 无 Cache-Control 头 -> Chromium 启发式缓存(≈(now-LastModified)/10) 复用陈旧副本,重启仍命中旧 JSON,仅删 Cache 目录才生效 --- electron/main/index.ts | 9 +++++++++ src/App.vue | 15 +++++++++++++++ src/global/storeConfig.ts | 14 ++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/electron/main/index.ts b/electron/main/index.ts index ce217580..10d04579 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -652,6 +652,15 @@ app.whenReady().then(() => { // Set User-Agent for client session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => { details.requestHeaders["User-Agent"] = getUserAgent(); + // 数据 JSON(applist / categories / priority-config / sidebar-config 等)禁用客户端缓存。 + // nginx 默认不发 Cache-Control,Chromium 会按启发式 TTL(≈(now-LastModified)/10)复用陈旧副本, + // 导致服务端上新应用后商店内仍搜不到、且重启无效(仅删 Cache 目录才生效)。 + // 注意:C2 会给 URL 追加 ?_t=... 版本戳,故需按 query 前的 pathname 判断,而非 endsWith(".json")。 + const dataUrlPath = details.url.split("?")[0]; + if (dataUrlPath.endsWith(".json")) { + details.requestHeaders["Cache-Control"] = "no-cache"; + details.requestHeaders["Pragma"] = "no-cache"; + } callback({ cancel: false, requestHeaders: details.requestHeaders }); }); createWindow(); diff --git a/src/App.vue b/src/App.vue index 6b3da917..284bcc3f 100644 --- a/src/App.vue +++ b/src/App.vue @@ -429,6 +429,21 @@ const axiosInstance = axios.create({ timeout: 5000, // 增加到 5 秒,避免网络波动导致的超时 }); +// C2:数据 JSON(applist / categories / sidebar-config 等)追加 ?_t 版本戳, +// 使每次 URL 不同,穿透 CDN 边缘缓存,确保返回最新列表。 +// 与主进程 onBeforeSendHeaders 注入的 no-cache 互为兜底(C1 已对 Chromium 磁盘缓存生效)。 +axiosInstance.interceptors.request.use((config) => { + if (config.method?.toLowerCase() === "get" && typeof config.url === "string") { + // 按去除 query 的 pathname 判断,兼容 C2 自身追加的 ?_t= 及任何既有 query + const reqPath = config.url.split("?")[0]; + if (reqPath.endsWith(".json")) { + const sep = config.url.includes("?") ? "&" : "?"; + config.url = `${config.url}${sep}_t=${Date.now()}`; + } + } + return config; +}); + const fetchWithRetry = async ( url: string, signal?: AbortSignal, diff --git a/src/global/storeConfig.ts b/src/global/storeConfig.ts index ab76a17f..4768dcde 100644 --- a/src/global/storeConfig.ts +++ b/src/global/storeConfig.ts @@ -12,6 +12,20 @@ const priorityConfigAxios = axios.create({ timeout: 10000, }); +// C2:priority-config.json 走独立 axios 实例(不经过 axiosInstance), +// 同样追加 ?_t 版本戳以穿透 CDN 边缘缓存,与 C1 的 no-cache 注入互为兜底。 +priorityConfigAxios.interceptors.request.use((config) => { + if (config.method?.toLowerCase() === "get" && typeof config.url === "string") { + // 按去除 query 的 pathname 判断,兼容 C2 自身追加的 ?_t= 及任何既有 query + const reqPath = config.url.split("?")[0]; + if (reqPath.endsWith(".json")) { + const sep = config.url.includes("?") ? "&" : "?"; + config.url = `${config.url}${sep}_t=${Date.now()}`; + } + } + return config; +}); + export const APM_STORE_STATS_BASE_URL: string = import.meta.env.VITE_APM_STORE_STATS_BASE_URL || "";