我会对照方案读取现有接口保存、参数实体和转发组装代码,判断改造影响面与风险点。 Created 4 todos Searched for files matching `**/src/InterfaceForward.Repositories/**/*.cs`, 80 matches 我会并行读取关键实体、DTO、保存查询服务和转发构建代码,形成可行性判断。 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Repositories/Parameter/Entities/ParameterEntity.cs) Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Repositories/Parameter/Entities/FormParameterEntity.cs) Searched for files matching `**/src/**/FixedParameter*.cs`, 5 matches Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Repositories/Parameter/Entities/FixedParameterEntity.cs) Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application.Contracts/Dtos/Interface/SaveInterfaceInput.cs) Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application.Contracts/Dtos/Interface/ParameterInput.cs) Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application.Contracts/Dtos/Interface/SaveParameterMapsInput.cs) Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application.Contracts/Dtos/Interface/ParameterParseOutput.cs) Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application.Contracts/Dtos/ServiceProvider/FixedParameterInput.cs) 我已读取实体和 DTO,下一步查看保存/查询接口与转发上下文构建,判断方案 B 的改动点是否闭环。 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application/Services/Interface/InterfaceService.cs#1-1), lines 1 to 260 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application/Services/Interface/InterfaceService.cs#260-260), lines 260 to 334 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application/Services/Parameter/ParameterService.cs#1-1), lines 1 to 260 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application/Services/Parameter/ParameterService.cs#260-260), lines 260 to 560 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application/Services/Parameter/FormParameterService.cs) 我继续读取上下文构建和映射查询代码,确认方案里 `InParamTreeList` 来源切换的实现难度。 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application/Services/InterfaceForwardCommon.cs#1-1), lines 1 to 260 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Application/Services/InterfaceForwardCommon.cs#260-260), lines 260 to 420 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Repositories/InterfaceForwardQuery.cs) 关键转发查询显示目前仍把下游所有 `IsInPara=true` 当映射树,且 Form KV 未区分 Query/Header/Body;我再查看 DTO/枚举常量后给出结论。 Searched for regex `enum FieldPosition|enum ContentType|FromBody|FromMappingBody|FormFieldList|FixedFieldList` (`**/src/**`), 79 results Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Domain.Shared/Enum/FieldPosition.cs) Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Domain.Shared/Enum/ContentType.cs) 已有 `FieldPosition` 和 `ContentType` 枚举基本符合方案,但 `t_parameter_form` 实体缺 `FieldPosition`,`t_parameter` 缺 `ParaKind`,这是数据库层主要增量。 Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Domain.Shared/GlobalConst.cs) Read [](file:///d%3A/my/itfx/itfx/src/InterfaceForward.Domain.Shared/Dtos/ForwardCoreContextCache.cs) Completed: *梳理现有数据模型* (1/4) 可行,但这是**中大型重构**,不是小改。方案 B 和当前代码方向一致,主要是把现在“下游入参树 + 表单参数 + 固定参数”混用的问题拆清楚。建议可以做,但要按阶段推进。 ## 总体结论 **可行性:高。** **改造成本:中高。** **主要风险:映射保存/发布缓存/转发组装三处需要同步改,否则容易出现保存成功但转发错误。** 方案 B 的核心改动和现有代码冲突点主要有 3 个: 1. 当前下游统一使用 `InParameterList` 作为映射树。 2. 当前 `t_parameter_form` 没有 `FieldPosition`,无法区分 Query / Header / Body。 3. 当前转发时 FormUrlEncoded 用 `$FromBody`,方案要求改成 `$FromMappingBody`。 --- ## 当前代码现状 ### 1. `t_parameter` 当前只有 `IsInPara` 实体在 ParameterEntity.cs: ```csharp public bool IsInPara { get; set; } ``` 目前语义是: - `IsInPara = true`:入参 - `IsInPara = false`:出参 但方案 B 需要进一步区分: - 上游入参 - 下游 Json/Xml RequestBody - 下游 FormUrlEncoded MappingBody - 出参 所以需要新增: ```csharp public ParameterParaKind ParaKind { get; set; } ``` 或类似枚举: ```csharp public enum ParameterParaKind { Normal = 0, MappingBody = 1 } ``` ### 2. `t_parameter_form` 当前没有 `FieldPosition` 实体在 FormParameterEntity.cs,当前只有: ```csharp public string Name { get; set; } public string Value { get; set; } public string Description { get; set; } ``` 方案 B 要它承载: - Query KV - Header KV - Body KV 所以必须新增: ```csharp public FieldPosition FieldPosition { get; set; } ``` 现有 `FieldPosition` 枚举已经存在于 FieldPosition.cs,可直接复用。 ### 3. `SaveInterfaceInput` 当前字段不够 当前 SaveInterfaceInput.cs 只有: ```csharp public List InParameterList { get; set; } public List OutParameterList { get; set; } public List FormParameterList { get; set; } ``` 方案 B 要改成: ```csharp public List QueryFormParameterList { get; set; } public List HeaderFormParameterList { get; set; } public List BodyFormParameterList { get; set; } public List InParameterList { get; set; } public List RequestBodyParameterList { get; set; } public List MappingBodyParameterList { get; set; } public List OutParameterList { get; set; } ``` 不做旧字段兼容的话,这个改动是合理的。 --- ## 转发逻辑可行性 ### 当前链路 当前构建转发上下文在 InterfaceForwardQuery.cs: ```csharp var inParaMaps = await GetParameterMapListAsync(mapIds, true); ... InParamTreeList = JsonHelper.BuildTreeList(items) FormFieldList = await GetFormFieldListAsync(targetInterface.Id) FixedFieldList = fixedFieldList ``` 当前问题是: - 下游所有 `IsInPara=true` 都被当成映射目标。 - FormUrlEncoded 和 Json 的映射树没有语义区分。 - Query/Header 主要还依赖 `FixedFieldList` 或旧 `FormFieldList`。 方案 B 的调整是可落地的: | ContentType | `InParamTreeList` 来源 | | -------------- | -------------------------- | | Json / Xml | `requestBodyParameterList` | | FormUrlEncoded | `mappingBodyParameterList` | | 上游 | `inParameterList` | 这需要改 `GetParameterMapListAsync()` 查询条件: - Json/Xml:查 `t_parameter.IsInPara = true AND ParaKind = Normal` - FormUrlEncoded:查 `t_parameter.IsInPara = true AND ParaKind = MappingBody` - 出参:仍查 `IsInPara = false` --- ## HTTP 组装改造可行性 当前 DefaultForwardFlow.cs 已经有这些能力: - Query 拼接 - Header 拼接 - FormUrlEncoded Body 组装 - Json/XML Body 序列化 - 占位符替换 所以不是推倒重来,而是调整来源。 ### 当前 FormUrlEncoded 当前逻辑大致是: ```csharp if (context.FormFieldList.Count != 0) { var field = context.FormFieldList.FirstOrDefault(x => x.Value == GlobalConst.FromBody); if (field != null) field.Value = body; nameValueCollection = context.FormFieldList.ToDictionary(x => x.Name, x => x.Value); } ``` 方案 B 要改为: ```csharp $FromMappingBody ``` 并且 `FormFieldList` 只取 `FieldPosition = Body`。 Query/Header 不应该混在 `FixedFieldList` 的接口级配置里,而应来自: ```csharp queryFormParameterList headerFormParameterList ``` --- ## 数据库改造建议 需要新增字段: ### `t_parameter_form` ```sql ALTER TABLE t_parameter_form ADD FieldPosition INT NOT NULL DEFAULT 2; ``` 默认 `2 = Body`,这样老数据如果不迁移也能先当 Body。 ### `t_parameter` ```sql ALTER TABLE t_parameter ADD ParaKind INT NOT NULL DEFAULT 0; ``` 默认 `0 = Normal`。 如果真的“不做旧字段兼容,全量重构”,可以不迁移旧语义;但数据库字段还是要加。 --- ## 主要影响面 ### 必改 | 模块 | 文件/区域 | 影响 | | ---------------- | ----------------------- | ---------------------------------------------- | | DTO | `SaveInterfaceInput` | 入参结构重构 | | DTO | `FormParameterInput` | 新增 `FieldPosition` | | DTO | `ParameterInput` | 新增 `ParaKind` | | Entity | `FormParameterEntity` | 新增 `FieldPosition` | | Entity | `ParameterEntity` | 新增 `ParaKind` | | SaveInterface | `InterfaceService` | 按 ContentType 互斥保存 | | GetInterfaceById | `InterfaceService` | 按 ContentType 拆分返回 | | 参数服务 | `ParameterService` | 保存/查询支持 `ParaKind` | | 表单服务 | `FormParameterService` | 保存/查询支持 `FieldPosition` | | 转发查询 | `InterfaceForwardQuery` | 映射树按 ContentType 选择 | | 转发执行 | `DefaultForwardFlow` | `$FromMappingBody`、Query/Header/Form 来源调整 | ### 可能要改 | 模块 | 原因 | | ---------------------------- | --------------------------------------------------------- | | `InterfaceMapService` | 映射页面可能依赖下游 `InParameterList` | | `InterfaceMapPublishService` | 发布缓存构建依赖参数树 | | `FixedParameterService` | 方案要求删除接口级 Fixed 维护 | | 导入导出 | 如果导出接口配置,需要更新结构 | | 脚本助手 | 需要支持 `$FromMappingBody` 和新的 Query/Header/Body 结构 | --- ## 最大风险点 ### 1. 映射页面风险最高 当前映射保存结构在 SaveParameterMapsInput.cs。 它的 `ParaId` 指向下游参数。 方案 B 后: - Json/Xml 下游:`ParaId` 指向 `requestBodyParameterList` - FormUrlEncoded 下游:`ParaId` 指向 `mappingBodyParameterList` - Header/Query/BodyForm KV 不参与普通参数映射,除非值为 `$FromMappingBody` 这个规则必须前后端统一,否则映射会乱。 ### 2. 缓存风险 转发上下文会缓存: ```csharp ForwardContext:up_{upStreamCode}:sp_{serviceProviderCode} ``` 重构后发布接口/保存接口必须清理或重建缓存,否则会拿旧结构转发。 ### 3. FormUrlEncoded 行为变化 旧逻辑用 `$FromBody`,新逻辑用 `$FromMappingBody`。 如果现有表单配置里已经有 `$FromBody`,全量重构可以不兼容,但测试环境必须重新配置。 ### 4. 接口级 Fixed 删除要谨慎 `t_parameter_fixed` 当前支持: ```csharp ServiceProviderId InterfaceId ``` 方案要求删除接口级 Fixed 维护,但代码里 InterfaceForwardQuery.cs 仍会查: ```csharp a.ServiceProviderId == serviceProviderId || a.InterfaceId == interfaceId ``` 如果彻底删除接口级 Fixed,需要改成只查服务商级: ```csharp a.ServiceProviderId == serviceProviderId ``` 否则旧数据仍会生效。 --- ## 推荐实施顺序 ### 第一阶段:数据模型和 DTO 1. 新增 `ParameterParaKind` 枚举。 2. `ParameterEntity` 新增 `ParaKind`。 3. `ParameterInput` 新增 `ParaKind`。 4. `FormParameterEntity` 新增 `FieldPosition`。 5. `FormParameterInput` / `FormParameterItem` 新增 `FieldPosition`。 6. `SaveInterfaceInput` 拆分字段。 ### 第二阶段:保存/查询接口 改 InterfaceService.cs: - 上游:只保存 `inParameterList` - 下游 Json/Xml:只保存 `requestBodyParameterList` - 下游 FormUrlEncoded:保存 `bodyFormParameterList` + `mappingBodyParameterList` - 所有类型:保存 `queryFormParameterList` + `headerFormParameterList` - 所有类型:保存 `outParameterList` 并加入互斥校验。 ### 第三阶段:转发查询 改 InterfaceForwardQuery.cs: - `GetParameterMapListAsync()` 支持 `ParaKind` - `GetFormFieldListAsync()` 改成按 `FieldPosition` 获取 - 构建 `TargetInterfaceSummary` 时区分: - `QueryFieldList` - `HeaderFieldList` - `BodyFormFieldList` - `InParamTreeList` ### 第四阶段:转发执行 改 DefaultForwardFlow.cs: - `ReplacePlaceholder()` 支持 `$FromMappingBody` - Query 从 Query KV 来 - Header 从 Header KV 来 - FormUrlEncoded Body 从 Body KV 来 - Json/Xml Body 保持序列化 `OriginalInterfaceMappedInput` ### 第五阶段:映射与发布 重点改: - 映射详情查询 - 映射保存 - 发布缓存 - 缓存清理 ### 第六阶段:测试 建议新增测试覆盖: 1. 下游 Json:`requestBodyParameterList` 映射并序列化为 JSON。 2. 下游 Xml:`requestBodyParameterList` 映射并序列化为 XML。 3. FormUrlEncoded:`mappingBodyParameterList` 映射,`bodyFormParameterList` 中 `$FromMappingBody` 被替换。 4. Query:所有 ContentType 都能拼 Query。 5. Header:所有 ContentType 都能加 Header。 6. 上游:仍只使用 `inParameterList`。 7. 接口级 Fixed 不再生效。 8. 服务商级 Fixed 仍生效。 --- ## 可行性评级 | 项 | 评级 | | ---------------------- | ---------------------------- | | 技术可行性 | 高 | | 代码改动量 | 中高 | | 数据库改动风险 | 中 | | 前端联动成本 | 高 | | 转发链路风险 | 中高 | | 是否建议做 | 建议做 | | 是否适合一次性全量重构 | 可以,但必须有测试和联调环境 | --- ## 最终建议 方案 B 是正确方向,尤其解决了当前这几个长期隐患: - Form 参数和 Query/Header 混用。 - 下游 `InParameterList` 语义不清。 - Json Body 和 Form Mapping Body 混用。 - `$FromBody` 表达不准确。 - 接口级 Fixed 和接口参数配置职责重叠。 建议按**全量重构**执行,但不要边改边猜。最好先做后端闭环: ```text DB 字段 → DTO → Save/Get → ForwardContext → ForwardFlow → Tests ``` 等后端测试跑通后,再让前端按方案 B 调整页面。