fix(form): 附件上传地址改用模块真实路由前缀,修请假佐证材料 404
build / build-push (push) Successful in 53s

用户上传请假佐证材料时请求打到 /homeleave/api/base/FileUpload,被网关直接 404。

根因:默认上传地址按 "/" + ToolDef.module + "/api/base/FileUpload" 拼 ——
把「模块 key」当成了路由前缀。而请假的 key 是 homeleave、真实前缀是
/home-leave(差一个连字符)。实测 /home-leave/... 回 302 走 CAS,
/homeleave/... 回 caddy 404。

- 新增 AgentOrchestrator.pathPrefix(module, baseUrl):从 agent.modules 的配置
  地址推出站点根下的路径前缀;未配置时退回 key,尾部斜杠会被吃掉
  (否则会拼出 //api/base/FileUpload)
- buildForm 的上传地址改用它拼接(作业仍走 uploadPathOverride,不受影响)
- 其余 4 个模块的 key 与前缀同名,行为不变(curl 实测 /campusnotice、
  /dormnotice、/familyactivity、/coursehomework/api/file/Upload 均 302 可达)
- 补 2 条契约测试锁住这个行为;并修正 ModuleFormParityTest 里被一并写错的
  homeleave 地址 —— 正是它把同一个错误复制进了测试,导致一直测不出来
This commit is contained in:
lijing
2026-10-13 16:36:15 +08:00
parent 53b3eaa39c
commit cb8764082d
2 changed files with 89 additions and 4 deletions
@@ -2,6 +2,7 @@ package com.yunhai.agent;
import com.yunhai.agent.config.AgentSettings;
import com.yunhai.agent.model.BrowserToolRequest;
import com.yunhai.agent.service.AgentOrchestrator;
import com.yunhai.agent.tool.FormField;
import com.yunhai.agent.tool.ToolDef;
import com.yunhai.agent.tool.ToolExecutor;
@@ -48,7 +49,9 @@ class ModuleFormParityTest {
settings.getModules().put("campusnotice", "http://base.yunhaixingtong.com/campusnotice");
settings.getModules().put("dormnotice", "http://base.yunhaixingtong.com/dormnotice");
settings.getModules().put("familyactivity", "http://base.yunhaixingtong.com/familyactivity");
settings.getModules().put("homeleave", "http://base.yunhaixingtong.com/homeleave");
// ★ 前缀是 /home-leave(差一个连字符)—— 早先这里跟着代码一起写成 /homeleave,
// 于是「附件上传地址拼错」这个 bug 在测试里也被一并复制、永远测不出来。
settings.getModules().put("homeleave", "http://base.yunhaixingtong.com/home-leave");
settings.getModules().put("coursehomework", "http://base.yunhaixingtong.com/coursehomework");
registry = new ToolRegistry(settings);
registry.init();
@@ -226,7 +229,45 @@ class ModuleFormParityTest {
call.getFollowUp().getPathAndQuery(), "第二步地址要带模块前缀,并留 {data} 给首步的 id");
}
/* ==================== ⑥ 附件控件渲染 ==================== */
/* ==================== ⑥ 附件上传地址:前缀必须取自配置,不能用模块 key 拼 ==================== */
/**
* ★ 回归:附件上传地址的前缀必须取自 `agent.modules` 的配置。
*
* <p>请假的 key 是 {@code homeleave},真实路由前缀是 {@code /home-leave} —— 差一个连字符。
* 早先按 {@code "/" + def.getModule() + "/api/base/FileUpload"} 拼,请求打到
* {@code /homeleave/api/base/FileUpload},被网关当成不存在的应用直接 **404**
* —— 用户上传佐证材料时实际撞到的就是这个。
*/
@Test
void uploadPathPrefixComesFromConfiguredUrlNotModuleKey() {
assertEquals("/home-leave",
AgentOrchestrator.pathPrefix("homeleave", "http://base.yunhaixingtong.com/home-leave"),
"请假的前缀带连字符,不能拿 key(homeleave) 顶替");
assertEquals("/home-leave/api/base/FileUpload",
AgentOrchestrator.pathPrefix("homeleave", "http://base.yunhaixingtong.com/home-leave")
+ "/api/base/FileUpload");
assertEquals("/campusnotice",
AgentOrchestrator.pathPrefix("campusnotice", "http://base.yunhaixingtong.com/campusnotice"));
assertEquals("/dormnotice",
AgentOrchestrator.pathPrefix("dormnotice", "http://base.yunhaixingtong.com/dormnotice/"),
"尾部斜杠要吃掉,否则会拼出 //api/base/FileUpload");
// 地址没有路径部分 / 完全未配置 → 退回 key 前缀,至少不会拼出空串
assertEquals("/x", AgentOrchestrator.pathPrefix("x", "http://host"));
assertEquals("/y", AgentOrchestrator.pathPrefix("y", null));
}
/** 四个走默认上传接口的模块都要能拼出「以 / 开头且无双斜杠」的地址 */
@Test
void everyModuleResolvesAnAbsoluteUploadPath() {
for (String m : Arrays.asList("campusnotice", "dormnotice", "familyactivity", "homeleave")) {
String p = AgentOrchestrator.pathPrefix(m, settings.getModules().get(m)) + "/api/base/FileUpload";
assertTrue(p.startsWith("/"), m + " 的上传地址要以 / 开头,实际:" + p);
assertFalse(p.contains("//"), m + " 的上传地址不能出现双斜杠,实际:" + p);
}
}
/* ==================== ⑦ 附件控件渲染 ==================== */
@Test
void scalarValueIsWrappedForArrayParams() {