From 52b665cd395c1b9965feec766c192fca05d21241 Mon Sep 17 00:00:00 2001 From: hjhan Date: Fri, 7 Aug 2026 17:53:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(otcformat):=20/front/otcformat=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=20NoStore,=E4=BF=AE=E5=A4=8D=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=90=8E=E7=BC=93=E5=AD=98=E4=B8=8D=E7=94=9F?= =?UTF-8?q?=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FrontController.OtcFormat 原使用 ResponseCache(Duration=600, Location=Any), 导致在 Admin 配置页保存 OtcFormat 后,前端最长 600s 内仍返回旧内容, 表现为'改了配置前端不起效果',需手工加 ?v= 才能破缓存。 改为 NoStore 后保存即对所有用户立即生效。 同时在 FrontController 类注释补充完整排查文档: - 三个同名 otcformat.js 文件的角色与路径 - DB AppConfig 真相源(PGroup=ProjectConfig, PName=OtcFormatConfig) - 写入/读取/启动三条数据流 - '前端不起效果'的 4 步排查顺序 - 多节点落盘只写当前节点的坑 OtcConfigController.AjaxSaveOtcFormat 补充多节点陷阱说明并指向 FrontController 文档。 --- .../Admin/Controllers/OtcConfigController.cs | 5 ++ YLErpWeb/Controllers/FrontController.cs | 52 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/YLErpWeb/Areas/Admin/Controllers/OtcConfigController.cs b/YLErpWeb/Areas/Admin/Controllers/OtcConfigController.cs index dd95f9a2..353c4d91 100644 --- a/YLErpWeb/Areas/Admin/Controllers/OtcConfigController.cs +++ b/YLErpWeb/Areas/Admin/Controllers/OtcConfigController.cs @@ -108,6 +108,11 @@ namespace YLErp.Web.Areas.Admin.Controllers /// /// 保存配置 /// + /// + /// 保存链路:写 DB(AppConfig.OtcFormatConfig) → 落盘 App_Data/Config/otcformat.js → 刷新内存。 + /// 注意:File.WriteAllText 只写当前节点磁盘。多节点部署下,未处理本次请求的节点文件不会更新, + /// 会造成"DB 正确但 /front/otcformat 返回旧值"。完整排查见 FrontController 类注释。 + /// public JsonResult AjaxSaveOtcFormat(OtcFormatModel model) { if (model is null) diff --git a/YLErpWeb/Controllers/FrontController.cs b/YLErpWeb/Controllers/FrontController.cs index 66234ef1..fb423e6a 100644 --- a/YLErpWeb/Controllers/FrontController.cs +++ b/YLErpWeb/Controllers/FrontController.cs @@ -10,6 +10,50 @@ namespace YLErp.Web.Controllers /// 专用于输出前端JS的控制器 /// 数据必须为非敏感数据 /// + /// + /// ============================================================ + /// OtcFormat 配置链路 & 排查说明(改前端格式化"不起效果"先看这里) + /// ============================================================ + /// + /// 【三个同名文件,角色不同】 + /// 1. wwwroot/Scripts/init/otcformat.js —— 出厂默认值(兜底种子),Git 管理 + /// 2. wwwroot/Scripts/base/otcformat.js —— 格式化引擎(运行时逻辑),Git 管理 + /// 依赖 lodash.js / main.numberFormat / jQuery,且须先加载"配置段"再加载引擎 + /// 3. App_Data/Config/otcformat.js —— 运行时配置文件(真正生效那份),非 Git 管理 + /// 内容形如: var main = main || {}; main.formatOptions = { trading: {...} }; + /// + /// 【配置真相源:DB AppConfig 表】 + /// PGroup = "ProjectConfig", PName = "OtcFormatConfig" (见 ConsAppConfig.OtcFormatConfig) + /// App_Data/Config/otcformat.js 只是 DB 配置落盘的镜像。 + /// + /// 【写入链路】OtcConfigController.AjaxSaveOtcFormat (Admin 配置页"保存"): + /// 表单 model → JsonConvert.SerializeObject + /// → AppConfigService.SaveOtcFormatConfig 写 DB + /// → File.WriteAllText(App_Data/Config/otcformat.js) 落盘(只写当前节点!) + /// → OtcFormatHelper.Initialize 刷新服务端内存 + /// + /// 【读取链路】FrontController.OtcFormat (前端 GET /front/otcformat): + /// 读 App_Data/Config/otcformat.js + Scripts/base/otcformat.js 拼接返回 + /// 前端引擎 base/otcformat.js 用 main.formatOptions 覆盖内置默认值 + /// + /// 【应用启动】AppManager (subSystem==OtcWeb): + /// DB 有配置 → 反序列化进 OtcFormatHelper + 落盘 App_Data/Config/otcformat.js + /// DB 为空 → 用 Scripts/init/otcformat.js 兜底种子落盘 + /// + /// 【排查"前端不起效果"按此顺序】 + /// ① 浏览器直访 /front/otcformat?v=随机数,看 main.formatOptions 是否最新 + /// · 加 ?v= 正确 / 不加错误 → ResponseCache 缓存(本接口已改 NoStore,不应再出现) + /// · 加了 ?v= 仍错误 → 进 ② + /// ② 查 DB AppConfig(OtcFormatConfig).PValue 是否最新 + /// · DB 空/旧 → AjaxSaveOtcFormat 没成功,查配置页 POST 响应 + /// ③ 直接读服务器 App_Data/Config/otcformat.js 是否最新 + /// · DB 对但文件旧 → AjaxSaveOtcFormat 的 File.WriteAllText 没生效, + /// 或多节点负载均衡下只写了接收 POST 的那台(读取命中了另一台旧文件)。 + /// 读取和写入都只操作本机 Server.MapPath,无跨节点同步——多节点部署需注意。 + /// ④ 页面引用方式:必须走 /front/otcformat,不能直接引 base/otcformat.js + /// (后者只有引擎默认值,没有配置段),例如 wwwroot/Scripts/test/tradeCalc.html 即如此。 + /// ============================================================ + /// [MyAuthorizeIgnore] public class FrontController : BaseController { @@ -21,9 +65,13 @@ namespace YLErp.Web.Controllers return Content(js, "text/javascript"); } - //格式化选项(缓存600s) + //格式化选项(配置动态变更,禁用缓存——见下方 OtcFormat 排查说明) [AllowAnonymous] - [ResponseCache(Duration = 600, Location = ResponseCacheLocation.Any)] + //重要:此处不能用 [ResponseCache(Duration=600,Location=Any)]。 + // 原因:OtcFormat 是会动态变更的运行时配置(见 OtcConfigController.AjaxSaveOtcFormat), + // 若启用缓存,Admin 页保存后最长 600s 内仍返回旧内容,"前端改了配置不起效果"。 + // 此前曾用 Duration=600,导致保存后必须等缓存过期或加 ?v=随机数 才生效。 + [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)] public ActionResult OtcFormat() { var js = string.Empty;