From 7a9702c707719b6fda9170bf297b2ce2d617a293 Mon Sep 17 00:00:00 2001 From: hjhan Date: Thu, 30 Jul 2026 11:23:58 +0800 Subject: [PATCH] =?UTF-8?q?fix(diag):=20JsVersion=20=E7=BA=B3=E5=85=A5?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=96=87=E4=BB=B6=20mtime=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E7=BA=AF=E5=89=8D=E7=AB=AF=E6=94=B9=E5=8A=A8=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E4=B8=8D=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因(?otcdebug=1 排查时暴露):JsVersion 只取 bin/YLErp*.dll 的 mtime, 纯前端改 wwwroot/Scripts 而不重编 DLL 时,?v= 缓存戳不变,浏览器仍加载旧版 ——即"发布了但不更新"。 修复: - JsVersion = max(DLL mtime, wwwroot/Scripts/** mtime, wwwroot/Statics/bundles/** mtime) - wwwroot 定位用 Directory.GetCurrentDirectory()(与 StaticUrlMiddleware 一致, 开发=项目根/部署=publish 目录),目录不存在则回退仅 DLL mtime - BinFileVersion 保持原义(仅 DLL,用于诊断显示后端构建时间) 附带修复 git 字段:AssemblyInformationalVersion 无 +sha(如固定版本 1.0.0)时, 回退从 .git/HEAD 读取当前 commit 短 sha,不再误显示 '1.0.0' 验证:dotnet build 0 错误 --- YLErpWeb/Common/HtmlUtil.cs | 82 ++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/YLErpWeb/Common/HtmlUtil.cs b/YLErpWeb/Common/HtmlUtil.cs index 1292f24e..12b6ed9c 100644 --- a/YLErpWeb/Common/HtmlUtil.cs +++ b/YLErpWeb/Common/HtmlUtil.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Html; +using System.IO; using System.Reflection; using YLErp.Events; @@ -27,18 +28,44 @@ namespace YLErp static HtmlUtil() { - //获取bin目录中YLErp开头的文件最后修改日期作为JS和CSS文件版本 + //获取bin目录中YLErp开头的文件最后修改日期作为后端构建版本 var binDir = new DirectoryInfo(AppContext.BaseDirectory); var files = binDir.GetFiles("YLErp*"); BinFileVersion = files.Any() ? files.Max(n => n.LastWriteTime) : DateTime.MinValue; - JsVersion = BinFileVersion.ToString("yyMMddHHmmss"); + + //JsVersion(浏览器 ?v= 缓存戳)必须同时反映【后端 DLL】和【前端脚本】的变更: + //历史上只取 DLL mtime,导致纯前端改动(改 wwwroot/Scripts 而不重编 DLL)时 + //缓存戳不变、浏览器仍加载旧版——即"发布了但不更新"(见 ?otcdebug=1 排查时的症状)。 + //现纳入 wwwroot/Scripts(业务脚本)+ wwwroot/Statics/bundles(打包产物)的 mtime 取 max。 + //wwwroot 定位用 Directory.GetCurrentDirectory()(与 StaticUrlMiddleware 一致, + //开发时=项目根、部署时=publish 目录),目录不存在则回退到仅 DLL mtime。 + var versionClock = BinFileVersion; + var webRoot = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"); + foreach (var sub in new[] { "Scripts", Path.Combine("Statics", "bundles") }) + { + var dir = Path.Combine(webRoot, sub); + if (Directory.Exists(dir)) + { + foreach (var f in new DirectoryInfo(dir).GetFiles("*", SearchOption.AllDirectories)) + { + if (f.LastWriteTime > versionClock) versionClock = f.LastWriteTime; + } + } + } + JsVersion = versionClock.ToString("yyMMddHHmmss"); //从 AssemblyInformationalVersion 读取 git sha(SDK 编译时已嵌入,零额外依赖) var infoVer = typeof(HtmlUtil).Assembly .GetCustomAttribute()?.InformationalVersion; - //格式 "1.0.0+",取 + 之后部分;无则回退到完整字符串 - GitCommit = string.IsNullOrEmpty(infoVer) ? "unknown" - : (infoVer.Contains('+') ? infoVer.Substring(infoVer.LastIndexOf('+') + 1) : infoVer); + //格式 "1.0.0+",取 + 之后部分;无 +(如固定版本号 1.0.0)则回退读 .git/HEAD + if (!string.IsNullOrEmpty(infoVer) && infoVer.Contains('+')) + { + GitCommit = infoVer.Substring(infoVer.LastIndexOf('+') + 1); + } + else + { + GitCommit = ReadGitCommitFromRepo() ?? (infoVer ?? "unknown"); + } EventBus.Subscribe(t => { @@ -46,6 +73,51 @@ namespace YLErp }); } + /// + /// 从 .git/HEAD 读取当前 commit 短 sha,作为 AssemblyInformationalVersion 无 sha 时的回退。 + /// 找不到 .git 或读取失败返回 null(不影响启动)。 + /// + static string ReadGitCommitFromRepo() + { + try + { + //从 ContentRoot 向上找 .git 目录(开发时在项目根/仓库根) + var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); + while (dir != null) + { + var gitDir = Path.Combine(dir.FullName, ".git"); + if (Directory.Exists(gitDir)) + { + return ParseGitHead(gitDir); + } + dir = dir.Parent; + } + } + catch { /* 读取失败不影响启动,返回 null */ } + return null; + } + + static string ParseGitHead(string gitDir) + { + var headFile = Path.Combine(gitDir, "HEAD"); + if (!File.Exists(headFile)) return null; + var head = File.ReadAllText(headFile).Trim(); + //HEAD 格式:"ref: refs/heads/xxx" 或 detached 时的直接 sha + if (head.StartsWith("ref: ")) + { + var refPath = Path.Combine(gitDir, head.Substring(5).Replace('/', Path.DirectorySeparatorChar)); + if (File.Exists(refPath)) + { + return File.ReadAllText(refPath).Trim().Substring(0, 12); + } + } + else if (head.Length >= 12) + { + return head.Substring(0, 12); + } + return null; + } + /// /// 获取基础数据JS连接 ///