From dedb4aa4362be93e7a0eb44dd556eeb0da159695 Mon Sep 17 00:00:00 2001 From: chenxing Date: Wed, 16 Sep 2026 02:08:55 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=9B=9E=E8=B0=83=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E8=A1=A5=20basePath=EF=BC=88=E4=BB=8E=E5=9B=9E=E8=B0=83=20URL?= =?UTF-8?q?=20=E6=8E=A8=E5=AF=BC=E6=8E=A5=E6=94=B6=E6=96=B9=20context-path?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 部署带 ctx(/svc-hall)时 flow-center 按整路径签名与 FlowCallbackVerifyFilter 剥 ctx 后对不上 → 注册探活 401 → service_flow_reg 缺失 → 办件状态事件全丢。 本地裸地址(无 ctx)推导为空串,行为不变。新增 FlowCenterClientCallbackBasePathTest。 --- .../service/impl/FlowCenterClient.java | 31 +++++++++++++++ .../FlowCenterClientCallbackBasePathTest.java | 38 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/test/java/com/yunhai/svchall/service/impl/FlowCenterClientCallbackBasePathTest.java diff --git a/src/main/java/com/yunhai/svchall/service/impl/FlowCenterClient.java b/src/main/java/com/yunhai/svchall/service/impl/FlowCenterClient.java index ebc1342..20f373d 100644 --- a/src/main/java/com/yunhai/svchall/service/impl/FlowCenterClient.java +++ b/src/main/java/com/yunhai/svchall/service/impl/FlowCenterClient.java @@ -145,6 +145,13 @@ public class FlowCenterClient implements FlowClient { if (eventTypes != null && !eventTypes.isEmpty()) { body.put("eventTypes", eventTypes); } + // 申报本服务 context-path(从回调 URL path 段推导,去掉尾部 /callback/flow): + // 推送方按它剥离后再签应用签名,与本服务 AppAuthFilter/FlowCallbackVerifyFilter 剥 + // contextPath 后的 target 对齐——本地裸地址(无 ctx)推导为空串,行为不变。 + String basePath = deriveCallbackBasePath(callbackUrl); + if (basePath != null && !basePath.isEmpty()) { + body.put("basePath", basePath); + } Map data = openCall.post(flowSpec, "/oapi/flow/callback/reg", Collections.singletonMap("schId", String.valueOf(schId)), body, Map.class); Object secret = data == null ? null : data.get("secret"); @@ -154,6 +161,30 @@ public class FlowCenterClient implements FlowClient { return String.valueOf(secret); } + /** + * 回调 URL → 接收方 context-path:取 URL path 段去掉尾部 "/callback/flow" + * (如 /svc-hall/callback/flow → /svc-hall;裸地址 /callback/flow → 空串)。 + * 包可见:契约测试冻结推导形态。 + */ + static String deriveCallbackBasePath(String callbackUrl) { + if (callbackUrl == null) { + return ""; + } + try { + String path = java.net.URI.create(callbackUrl.trim()).getPath(); + if (path == null || path.isEmpty()) { + return ""; + } + int idx = path.lastIndexOf("/callback/flow"); + if (idx > 0) { + return path.substring(0, idx); + } + return ""; + } catch (Exception e) { + return ""; + } + } + private static String trimTrailing(String s) { while (s.endsWith("/")) { s = s.substring(0, s.length() - 1); diff --git a/src/test/java/com/yunhai/svchall/service/impl/FlowCenterClientCallbackBasePathTest.java b/src/test/java/com/yunhai/svchall/service/impl/FlowCenterClientCallbackBasePathTest.java new file mode 100644 index 0000000..196332a --- /dev/null +++ b/src/test/java/com/yunhai/svchall/service/impl/FlowCenterClientCallbackBasePathTest.java @@ -0,0 +1,38 @@ +package com.yunhai.svchall.service.impl; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * 回调注册 basePath 推导契约:接收方 context-path 从回调 URL path 段去掉尾部 + * /callback/flow 推导(部署带 ctx=签名对齐关键;本地裸地址=空串保持旧形态)。 + * 2026-09-16 修复:注册漏带 basePath,flow-center 推送按整路径签名 → + * FlowCallbackVerifyFilter 剥 ctx 后对不上 → 401(本地无 ctx 掩盖)。 + */ +class FlowCenterClientCallbackBasePathTest { + + @Test + void derive_withContextPath() { + assertEquals("/svc-hall", + FlowCenterClient.deriveCallbackBasePath("http://svc-hall-service:10007/svc-hall/callback/flow")); + } + + @Test + void derive_bareLocalAddressIsEmpty() { + assertEquals("", FlowCenterClient.deriveCallbackBasePath("http://localhost:8086/callback/flow")); + } + + @Test + void derive_gatewayForm() { + assertEquals("/svc-hall", + FlowCenterClient.deriveCallbackBasePath("http://base.yunhaixingtong.com/svc-hall/callback/flow")); + } + + @Test + void derive_malformedOrNullSafe() { + assertEquals("", FlowCenterClient.deriveCallbackBasePath(null)); + assertEquals("", FlowCenterClient.deriveCallbackBasePath("")); + assertEquals("", FlowCenterClient.deriveCallbackBasePath("::::")); + } +}