fix(desktop-runtime): 修复桌面端重装后仍命中旧 UI 缓存

- 启动打包版时按 UI buildId 检测并清理 renderer 缓存
- 记录 lastSeenUiBuildId,避免每次启动都重复清缓存
- 调整 SPA 静态资源缓存策略,index.html/200.html/_payload.json 禁止缓存
- 保留 _nuxt 哈希资源长期缓存,减少必须在卸载时删除数据后才生效的问题
This commit is contained in:
2977094657
2026-03-11 13:11:39 +08:00
Unverified
parent b001596fcb
commit 3587ea4eaa
2 changed files with 91 additions and 4 deletions
+31 -4
View File
@@ -99,9 +99,36 @@ class _SPAStaticFiles(StaticFiles):
self._fallback_200 = Path(str(self.directory)) / "200.html"
self._fallback_index = Path(str(self.directory)) / "index.html"
async def get_response(self, path: str, scope): # type: ignore[override]
@staticmethod
def _normalize_path(path: str) -> str:
return str(path or "").strip().lstrip("/")
@classmethod
def _is_shell_path(cls, path: str) -> bool:
normalized = cls._normalize_path(path)
return normalized in {"", "index.html", "200.html", "_payload.json"} or normalized.startswith(
"_payload.json/"
)
@classmethod
def _apply_cache_headers(cls, path: str, response):
normalized = cls._normalize_path(path)
try:
return await super().get_response(path, scope)
if cls._is_shell_path(normalized):
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
elif normalized.startswith("_nuxt/"):
response.headers.setdefault("Cache-Control", "public, max-age=31536000, immutable")
except Exception:
pass
return response
async def get_response(self, path: str, scope): # type: ignore[override]
normalized = self._normalize_path(path)
try:
response = await super().get_response(path, scope)
return self._apply_cache_headers(normalized, response)
except StarletteHTTPException as exc:
if exc.status_code != 404:
raise
@@ -112,8 +139,8 @@ class _SPAStaticFiles(StaticFiles):
raise
if self._fallback_200.exists():
return FileResponse(str(self._fallback_200))
return FileResponse(str(self._fallback_index))
return self._apply_cache_headers("200.html", FileResponse(str(self._fallback_200)))
return self._apply_cache_headers("index.html", FileResponse(str(self._fallback_index)))
def _maybe_mount_frontend() -> None: