diff --git a/internal/logic/update/checker.go b/internal/logic/update/checker.go index 75c9a8b..25a4e11 100644 --- a/internal/logic/update/checker.go +++ b/internal/logic/update/checker.go @@ -35,8 +35,8 @@ func CheckForUpdate(ctx context.Context, force bool) (*CheckResult, error) { } } - // Call GitHub API - release, etag, err := fetchLatestRelease(ctx) + // Call GitHub API(force 时不带 ETag 条件请求,见 fetchLatestRelease 注释) + release, etag, err := fetchLatestRelease(ctx, !force) if err != nil { return nil, fmt.Errorf("failed to fetch latest release: %w", err) } @@ -120,8 +120,11 @@ func CheckForUpdate(ctx context.Context, force bool) (*CheckResult, error) { return result, nil } -// fetchLatestRelease calls the GitHub Releases API with conditional request support -func fetchLatestRelease(ctx context.Context) (*GitHubRelease, string, error) { +// fetchLatestRelease calls the GitHub Releases API. +// conditional 为 true 时携带 If-None-Match ETag 做条件请求(省配额); +// 强制检测(force)必须传 false:GitHub /releases/latest 有 CDN 缓存,刚发布新版本后 +// 条件请求可能返回过期的 304 Not Modified,导致强制检测仍拿不到最新发行版。 +func fetchLatestRelease(ctx context.Context, conditional bool) (*GitHubRelease, string, error) { url := githubAPIBase + "/releases/latest" req, err := http.NewRequestWithContext(ctx, "GET", url, nil) @@ -133,9 +136,11 @@ func fetchLatestRelease(ctx context.Context) (*GitHubRelease, string, error) { req.Header.Set("X-GitHub-Api-Version", "2022-11-28") // Add ETag for conditional request - if etagVal := manager.lastETag.Load(); etagVal != nil { - if etag, ok := etagVal.(string); ok && etag != "" { - req.Header.Set("If-None-Match", etag) + if conditional { + if etagVal := manager.lastETag.Load(); etagVal != nil { + if etag, ok := etagVal.(string); ok && etag != "" { + req.Header.Set("If-None-Match", etag) + } } } diff --git a/web/admin/src/views/AdminLayout.vue b/web/admin/src/views/AdminLayout.vue index 6d93f7f..8b79d79 100644 --- a/web/admin/src/views/AdminLayout.vue +++ b/web/admin/src/views/AdminLayout.vue @@ -58,6 +58,7 @@ const updateModalVisible = ref(false) const updateLoading = ref(false) const executing = ref(false) const rollingBack = ref(false) +const checking = ref(false) const updateStatus = ref(null) const releaseNotes = ref('') const releaseUrl = ref('') @@ -129,6 +130,16 @@ function openUpdateModal() { checkUpdate() // 打开弹窗时刷新版本检查,确保当前版本/最新版本为最新 } +// 立即检测:force=true 跳过后端检查缓存,强制向上游拉取最新版本信息 +async function manualCheck() { + checking.value = true + try { + await Promise.all([fetchUpdateStatus(), checkUpdate(true)]) + } finally { + checking.value = false + } +} + function closeUpdateModal() { updateModalVisible.value = false stopPolling() @@ -717,6 +728,9 @@ onUnmounted(() => { +