mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-09-20 21:50:11 +08:00
fix(cache): 列表/分类请求禁用客户端缓存,根治新应用上架后搜不到
- 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 目录才生效
This commit is contained in:
@@ -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();
|
||||
|
||||
+15
@@ -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 <T,>(
|
||||
url: string,
|
||||
signal?: AbortSignal,
|
||||
|
||||
@@ -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 || "";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user