feat:支持none
This commit is contained in:
parent
9e9cadddff
commit
df9afe876b
@ -411,6 +411,8 @@ public class DefaultForwardFlow : IForwardFlow, ITransientDependency
|
|||||||
string contentType;
|
string contentType;
|
||||||
switch (context.TargetInterface.ContentType)
|
switch (context.TargetInterface.ContentType)
|
||||||
{
|
{
|
||||||
|
case ContentType.None:
|
||||||
|
return;
|
||||||
case ContentType.FormUrlEncoded:
|
case ContentType.FormUrlEncoded:
|
||||||
Dictionary<string, string> nameValueCollection;
|
Dictionary<string, string> nameValueCollection;
|
||||||
if (context.FormFieldList.Count != 0)
|
if (context.FormFieldList.Count != 0)
|
||||||
@ -456,6 +458,9 @@ public class DefaultForwardFlow : IForwardFlow, ITransientDependency
|
|||||||
var body = context.OriginalInterfaceMappedInput;
|
var body = context.OriginalInterfaceMappedInput;
|
||||||
switch (context.TargetInterface.ContentType)
|
switch (context.TargetInterface.ContentType)
|
||||||
{
|
{
|
||||||
|
case ContentType.None:
|
||||||
|
data = string.Empty;
|
||||||
|
break;
|
||||||
case ContentType.Json:
|
case ContentType.Json:
|
||||||
data = JsonConvert.SerializeObject(body);
|
data = JsonConvert.SerializeObject(body);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -366,6 +366,10 @@ public class InterfaceService : ApplicationService
|
|||||||
|
|
||||||
switch (input.ContentType)
|
switch (input.ContentType)
|
||||||
{
|
{
|
||||||
|
case ContentType.None:
|
||||||
|
if (input.InParameterList.Count > 0 || input.RequestBodyParameterList.Count > 0 || input.MappingBodyParameterList.Count > 0 || input.BodyFormParameterList.Count > 0)
|
||||||
|
throw new BusinessException(message: "None 下游接口只能维护 Query/Header/Response");
|
||||||
|
break;
|
||||||
case ContentType.Json:
|
case ContentType.Json:
|
||||||
case ContentType.Xml:
|
case ContentType.Xml:
|
||||||
if (input.InParameterList.Count > 0 || input.MappingBodyParameterList.Count > 0 || input.BodyFormParameterList.Count > 0)
|
if (input.InParameterList.Count > 0 || input.MappingBodyParameterList.Count > 0 || input.BodyFormParameterList.Count > 0)
|
||||||
@ -392,6 +396,8 @@ public class InterfaceService : ApplicationService
|
|||||||
|
|
||||||
switch (input.ContentType)
|
switch (input.ContentType)
|
||||||
{
|
{
|
||||||
|
case ContentType.None:
|
||||||
|
break;
|
||||||
case ContentType.Json:
|
case ContentType.Json:
|
||||||
case ContentType.Xml:
|
case ContentType.Xml:
|
||||||
await ParameterService.CreateParametersAsync(input.RequestBodyParameterList, interfaceId, true);
|
await ParameterService.CreateParametersAsync(input.RequestBodyParameterList, interfaceId, true);
|
||||||
@ -413,6 +419,8 @@ public class InterfaceService : ApplicationService
|
|||||||
|
|
||||||
switch (input.ContentType)
|
switch (input.ContentType)
|
||||||
{
|
{
|
||||||
|
case ContentType.None:
|
||||||
|
break;
|
||||||
case ContentType.Json:
|
case ContentType.Json:
|
||||||
case ContentType.Xml:
|
case ContentType.Xml:
|
||||||
await ParameterService.MaintainParametersAsync(input.RequestBodyParameterList, interfaceId, true);
|
await ParameterService.MaintainParametersAsync(input.RequestBodyParameterList, interfaceId, true);
|
||||||
|
|||||||
@ -1,10 +1,18 @@
|
|||||||
namespace InterfaceForward.Domain.Shared.Enum;
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Domain.Shared.Enum;
|
||||||
|
|
||||||
public enum ContentType
|
public enum ContentType
|
||||||
{
|
{
|
||||||
|
[Description("none")]
|
||||||
|
None = 0,
|
||||||
|
[Description("x-www-form-urlencoded")]
|
||||||
FormUrlEncoded = 1,
|
FormUrlEncoded = 1,
|
||||||
|
[Description("form-data")]
|
||||||
FormData,
|
FormData,
|
||||||
|
[Description("json")]
|
||||||
Json,
|
Json,
|
||||||
|
[Description("xml")]
|
||||||
Xml,
|
Xml,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -220,7 +220,9 @@ ORDER BY `b`.`Sort` ASC").ToListAsync();
|
|||||||
var paraKind = targetInterface.ContentType == ContentType.FormUrlEncoded
|
var paraKind = targetInterface.ContentType == ContentType.FormUrlEncoded
|
||||||
? ParameterParaKind.MappingBody
|
? ParameterParaKind.MappingBody
|
||||||
: ParameterParaKind.Normal;
|
: ParameterParaKind.Normal;
|
||||||
var inParaMaps = await GetParameterMapListAsync([map.Id], true, paraKind);
|
var inParaMaps = targetInterface.ContentType == ContentType.None
|
||||||
|
? []
|
||||||
|
: await GetParameterMapListAsync([map.Id], true, paraKind);
|
||||||
var items = inParaMaps.Where(x => x.InterfaceId == targetInterface.Id).ToList();
|
var items = inParaMaps.Where(x => x.InterfaceId == targetInterface.Id).ToList();
|
||||||
var fixedFieldList = await GetAllFixedFieldListAsync(serviceProvider.Id, targetInterface.Id);
|
var fixedFieldList = await GetAllFixedFieldListAsync(serviceProvider.Id, targetInterface.Id);
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,79 @@
|
|||||||
|
using InterfaceForward.Application.Contracts.ForwardCore;
|
||||||
|
using InterfaceForward.Application.ForwardCore;
|
||||||
|
using InterfaceForward.Domain.Shared;
|
||||||
|
using InterfaceForward.Domain.Shared.Dtos;
|
||||||
|
using InterfaceForward.Domain.Shared.Enum;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace InterfaceForward.Application.Tests;
|
||||||
|
|
||||||
|
public class DefaultForwardFlowTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SerializationBody_ShouldUseMappedInputForJson()
|
||||||
|
{
|
||||||
|
var flow = new TestForwardFlow();
|
||||||
|
var context = new ForwardCoreContext
|
||||||
|
{
|
||||||
|
TargetInterface = new InterfaceDto { ContentType = ContentType.Json },
|
||||||
|
OriginalInterfaceMappedInput = new JObject { ["orderId"] = "A001" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var body = flow.SerializationBody(context);
|
||||||
|
|
||||||
|
Assert.Equal("{\"orderId\":\"A001\"}", body);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SetContentType_ShouldReplaceFromMappingBodyForFormUrlEncoded()
|
||||||
|
{
|
||||||
|
var flow = new TestForwardFlow();
|
||||||
|
var context = new ForwardCoreContext
|
||||||
|
{
|
||||||
|
TargetInterface = new InterfaceDto { ContentType = ContentType.FormUrlEncoded },
|
||||||
|
TargetInterfaceInput = "{\"orderId\":\"A001\"}",
|
||||||
|
OriginalInterfaceMappedInput = new JObject { ["orderId"] = "A001" },
|
||||||
|
FormFieldList =
|
||||||
|
[
|
||||||
|
new InterfaceFormFieldDto
|
||||||
|
{
|
||||||
|
Name = "notifyBizEventDTO",
|
||||||
|
Value = GlobalConst.FromMappingBody
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
using var message = new HttpRequestMessage();
|
||||||
|
flow.SetContentTypeForTest(context, message);
|
||||||
|
|
||||||
|
var content = await message.Content!.ReadAsStringAsync();
|
||||||
|
|
||||||
|
Assert.Equal("notifyBizEventDTO=%7B%22orderId%22%3A%22A001%22%7D", content);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NoneContentType_ShouldNotCreateRequestContent()
|
||||||
|
{
|
||||||
|
var flow = new TestForwardFlow();
|
||||||
|
var context = new ForwardCoreContext
|
||||||
|
{
|
||||||
|
TargetInterface = new InterfaceDto { ContentType = ContentType.None },
|
||||||
|
OriginalInterfaceMappedInput = new JObject(),
|
||||||
|
TargetInterfaceInput = string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
using var message = new HttpRequestMessage();
|
||||||
|
flow.SetContentTypeForTest(context, message);
|
||||||
|
|
||||||
|
Assert.Equal(string.Empty, flow.SerializationBody(context));
|
||||||
|
Assert.Null(message.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestForwardFlow : DefaultForwardFlow
|
||||||
|
{
|
||||||
|
public void SetContentTypeForTest(ForwardCoreContext context, HttpRequestMessage message)
|
||||||
|
{
|
||||||
|
SetContentType(context, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,5 @@
|
|||||||
using InterfaceForward.Application.Contracts.Dtos.ScriptAssistant;
|
using InterfaceForward.Application.Contracts.Dtos.ScriptAssistant;
|
||||||
using InterfaceForward.Application.Contracts.ForwardCore;
|
|
||||||
using InterfaceForward.Application.ForwardCore;
|
|
||||||
using InterfaceForward.Application.Services.ScriptAssistant;
|
using InterfaceForward.Application.Services.ScriptAssistant;
|
||||||
using InterfaceForward.Domain.Shared;
|
|
||||||
using InterfaceForward.Domain.Shared.Dtos;
|
|
||||||
using InterfaceForward.Domain.Shared.Enum;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace InterfaceForward.Application.Tests;
|
namespace InterfaceForward.Application.Tests;
|
||||||
@ -76,57 +71,4 @@ public class ScriptAssistantServiceTests
|
|||||||
|
|
||||||
Assert.Contains(output.Warnings, x => x.Contains("System.IO"));
|
Assert.Contains(output.Warnings, x => x.Contains("System.IO"));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public class DefaultForwardFlowTests
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public void SerializationBody_ShouldUseMappedInputForJson()
|
|
||||||
{
|
|
||||||
var flow = new TestForwardFlow();
|
|
||||||
var context = new ForwardCoreContext
|
|
||||||
{
|
|
||||||
TargetInterface = new InterfaceDto { ContentType = ContentType.Json },
|
|
||||||
OriginalInterfaceMappedInput = new JObject { ["orderId"] = "A001" }
|
|
||||||
};
|
|
||||||
|
|
||||||
var body = flow.SerializationBody(context);
|
|
||||||
|
|
||||||
Assert.Equal("{\"orderId\":\"A001\"}", body);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task SetContentType_ShouldReplaceFromMappingBodyForFormUrlEncoded()
|
|
||||||
{
|
|
||||||
var flow = new TestForwardFlow();
|
|
||||||
var context = new ForwardCoreContext
|
|
||||||
{
|
|
||||||
TargetInterface = new InterfaceDto { ContentType = ContentType.FormUrlEncoded },
|
|
||||||
TargetInterfaceInput = "{\"orderId\":\"A001\"}",
|
|
||||||
OriginalInterfaceMappedInput = new JObject { ["orderId"] = "A001" },
|
|
||||||
FormFieldList =
|
|
||||||
[
|
|
||||||
new InterfaceFormFieldDto
|
|
||||||
{
|
|
||||||
Name = "notifyBizEventDTO",
|
|
||||||
Value = GlobalConst.FromMappingBody
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
using var message = new HttpRequestMessage();
|
|
||||||
flow.SetContentTypeForTest(context, message);
|
|
||||||
|
|
||||||
var content = await message.Content!.ReadAsStringAsync();
|
|
||||||
|
|
||||||
Assert.Equal("notifyBizEventDTO=%7B%22orderId%22%3A%22A001%22%7D", content);
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestForwardFlow : DefaultForwardFlow
|
|
||||||
{
|
|
||||||
public void SetContentTypeForTest(ForwardCoreContext context, HttpRequestMessage message)
|
|
||||||
{
|
|
||||||
SetContentType(context, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
372
方案B-重构清单-前后对比.md
372
方案B-重构清单-前后对比.md
@ -1,372 +0,0 @@
|
|||||||
# 方案 B 重构清单(前后对比 · 修订版)
|
|
||||||
|
|
||||||
> **前提**:全量重构,不做旧字段兼容。
|
|
||||||
> **修订要点**:先定义「一次 HTTP 请求」应保存哪些结构,再说明 **Mapping Body 仅在某些 Content-Type 下才存在**;`application/json` 的请求体参数树 **本身就是映射体**,不单独拆 Mapping Body。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. 设计顺序(先看这个)
|
|
||||||
|
|
||||||
```text
|
|
||||||
第一步 请求接口应保存什么(与 Content-Type 无关 + 有关部分分开)
|
|
||||||
Query / Header / Body 传输层 + 响应 + 基本信息
|
|
||||||
|
|
||||||
第二步 映射体放哪(由 Content-Type 决定)
|
|
||||||
Json/Xml → Body 参数树 = 映射体
|
|
||||||
Form 类 → 传输用表单 KV + 独立 Mapping Body 树(表单字段可 $FromMappingBody)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Mapping Body 不是每个接口都有**,只有「Body(或 Query)走表单 KV,且业务 JSON 需要单独做上游映射」时才配置。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. 改造后:一次请求应保存什么(目标模型)
|
|
||||||
|
|
||||||
### 2.1 与 Content-Type **无关**(任何下游接口都有)
|
|
||||||
|
|
||||||
| 存储 | 表 | UI(对齐 ApiTest) | 说明 |
|
|
||||||
|------|-----|-------------------|------|
|
|
||||||
| **基本信息** | `t_interface` | 地址、Method、Protocol、ContentType、QPS… | 不变 |
|
|
||||||
| **Query** | `t_parameter_form`(FieldPosition=**Query**) | Query Tab,KV | 真实 URL Query,不仅 FormUrlEncoded 才有 |
|
|
||||||
| **Header** | `t_parameter_form`(FieldPosition=**Header**) | Header Tab,KV | 请求头;占位符 $TimeStamp、$token 等 |
|
|
||||||
| **Response** | `t_parameter`(IsInPara=false) | Response 参数树 | 不变 |
|
|
||||||
| **返回配置** | `t_interface_return_config` | 返回配置 Tab | 不变 |
|
|
||||||
| **cURL 示例** | `t_interface.InParams` | cURL Tab | 不变 |
|
|
||||||
| **服务商级 Fixed** | `t_parameter_fixed`(ServiceProviderId) | 不在接口明细维护 | Url 占位、服务商通用 Header、脚本写入 |
|
|
||||||
|
|
||||||
### 2.2 与 Content-Type **有关**(Body 区不同)
|
|
||||||
|
|
||||||
| ContentType | Body 传输层保存什么 | 映射体保存什么 | 是否需要 Mapping Body |
|
|
||||||
|-------------|---------------------|----------------|------------------------|
|
|
||||||
| **Json (3)** | **`requestBodyParameterList`** 参数树 | **同一棵树** | **否** |
|
|
||||||
| **Xml (4)** | **`requestBodyParameterList`** 参数树 | **同一棵树** | **否** |
|
|
||||||
| **FormUrlEncoded (1)** | **`bodyFormParameterList`** KV | **`mappingBodyParameterList`** 参数树 | **是** |
|
|
||||||
| **FormData (2)** | 二期:`bodyForm` 或 multipart 描述 | 若字段内嵌 JSON,同 FormUrlEncoded | 二期 |
|
|
||||||
| **上游接口** | **`inParameterList`** 树(业务入参) | **同一棵树** | **否** |
|
|
||||||
|
|
||||||
### 2.3 结构总图(改造后)
|
|
||||||
|
|
||||||
```text
|
|
||||||
┌─ 基本信息 (t_interface)
|
|
||||||
│
|
|
||||||
任意 Content-Type ├─ queryFormParameterList (t_parameter_form, Query)
|
|
||||||
├─ headerFormParameterList (t_parameter_form, Header)
|
|
||||||
│
|
|
||||||
├─ Body 区 ─────────────────────────────────────┐
|
|
||||||
│ │
|
|
||||||
│ Json/Xml FormUrlEncoded │
|
|
||||||
│ requestBody bodyFormParameterList │
|
|
||||||
│ ParameterList (KV 传输) │
|
|
||||||
│ (树=映射体) mappingBodyParameterList │
|
|
||||||
│ (树=仅映射体) │
|
|
||||||
└────────────────────────────────────────────────┘
|
|
||||||
│
|
|
||||||
├─ outParameterList (出参树)
|
|
||||||
└─ inParams (cURL 示例)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.4 页面 Tab(下游接口 · 按 Content-Type 显示)
|
|
||||||
|
|
||||||
| Tab | Json / Xml | FormUrlEncoded |
|
|
||||||
|-----|------------|----------------|
|
|
||||||
| Query | 显示 KV | 显示 KV |
|
|
||||||
| Header | 显示 KV | 显示 KV |
|
|
||||||
| **Body** | **参数树**(= 映射体) | **KV 表**(传输) |
|
|
||||||
| **Mapping Body** | **隐藏** | **显示**(参数树) |
|
|
||||||
| cURL | 显示 | 显示 |
|
|
||||||
| Response | 显示 | 显示 |
|
|
||||||
| ~~固定配置~~ | 删除(接口级) | 删除 |
|
|
||||||
|
|
||||||
与 ApiTest 对齐方式:
|
|
||||||
|
|
||||||
- ApiTest 的 Request Tab:Json 时常用 Raw;**接口配置**里 Json 仍用 **参数树** 定义结构(itfx 现有能力,且即映射体)。
|
|
||||||
- ApiTest 的 FormUrlEncoded:URL Encoded KV = 我们的 **bodyForm**;映射结构不在调试页里,在接口配置里用 **Mapping Body** 维护。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Mapping Body 何时存在(规则定稿)
|
|
||||||
|
|
||||||
| 条件 | 结论 |
|
|
||||||
|------|------|
|
|
||||||
| `ContentType = Json` 或 `Xml` | **没有** `mappingBodyParameterList`;`requestBodyParameterList` 参与 `InParamRestructure` 且被 `SerializationBody` 序列化 |
|
|
||||||
| `ContentType = FormUrlEncoded` | **有** `bodyFormParameterList` + **有** `mappingBodyParameterList`;映射只对 Mapping Body 树;表单字段值可为 `$FromMappingBody` |
|
|
||||||
| Query 上也有「值为 JSON」的罕见情况 | 仍用 Mapping Body 树做映射,Query KV 里字段填 `$FromMappingBody`(与 Body 表单同理) |
|
|
||||||
| 上游 `IsUpStream=true` | 始终只有 **`inParameterList`**,无 Mapping Body、无 bodyForm |
|
|
||||||
|
|
||||||
**占位符**
|
|
||||||
|
|
||||||
| 占位符 | 用于 | Content-Type |
|
|
||||||
|--------|------|----------------|
|
|
||||||
| `$FromMappingBody` | Form 的 Query/Body(及必要时 Header)字段引用映射结果 | **仅 Form 类** |
|
|
||||||
| `$FromBody` | **删除**下游表单中的用法 | — |
|
|
||||||
| Json Body 树字段 | 直接映射到 alias,**不需要**占位符塞整段 JSON | Json / Xml |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. 数据库(修订)
|
|
||||||
|
|
||||||
### 4.1 `t_parameter_form` — 传输层 KV
|
|
||||||
|
|
||||||
**新增** `FieldPosition`:Header=1, Body=2, Query=3。
|
|
||||||
|
|
||||||
| FieldPosition | 何时有数据 |
|
|
||||||
|---------------|------------|
|
|
||||||
| Query | 任意 Content-Type,有 URL 参数就配 |
|
|
||||||
| Header | 任意 Content-Type |
|
|
||||||
| Body | **主要 FormUrlEncoded**;Json/Xml 通常 **无 body 行**(Body 在参数树) |
|
|
||||||
|
|
||||||
### 4.2 `t_parameter` — 参数树
|
|
||||||
|
|
||||||
**新增** `ParaKind`:
|
|
||||||
|
|
||||||
| ParaKind | 含义 | 用于 |
|
|
||||||
|----------|------|------|
|
|
||||||
| **0 Normal** | 默认 | 出参;**上游入参**;Json/Xml 的 **RequestBody** |
|
|
||||||
| **1 MappingBody** | 仅映射、不直接当 HTTP Json Body | **仅** FormUrlEncoded(及日后 FormData)且需要独立映射体时 |
|
|
||||||
|
|
||||||
| 列表字段 | ParaKind | IsInPara |
|
|
||||||
|----------|----------|----------|
|
|
||||||
| `requestBodyParameterList` | Normal(或枚举值 RequestBody=0) | true |
|
|
||||||
| `mappingBodyParameterList` | **MappingBody** | true |
|
|
||||||
| `outParameterList` | Normal | false |
|
|
||||||
|
|
||||||
**删除的用法**
|
|
||||||
|
|
||||||
- 不再用「一棵 in 树」同时表示 Form 映射 + Json Body(改造前混用)。
|
|
||||||
|
|
||||||
### 4.3 `t_parameter_fixed`
|
|
||||||
|
|
||||||
- **删**:接口明细维护接口级 Header/Query/Body KV。
|
|
||||||
- **留**:服务商级、Url、脚本动态 Header。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. SaveInterface / GetInterfaceById(请求结构)
|
|
||||||
|
|
||||||
`POST /api/Interface/SaveInterface` · 响应为接口 `id`(number)。
|
|
||||||
`GetInterfaceById` 字段与保存一致。已删除:`formParameterList`、下游 `inParameterList`。
|
|
||||||
|
|
||||||
### 5.1 根对象
|
|
||||||
|
|
||||||
| 字段 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `optionType` | `1` 增 / `3` 改 / `2` 删 |
|
|
||||||
| `isUpStream` | `true` 上游 / `false` 下游 |
|
|
||||||
| `serviceProviderId` | 上游 `0` |
|
|
||||||
| `id` | 改、删必填 |
|
|
||||||
| `name`, `requestAddress`, `requestProtocol`, `requestMethod`, `contentType` | 基本信息 |
|
|
||||||
| `code`, `category`, `description`, `isBatch`, `limit`, `responseContentType`, `flowCode`, `isDisableAuth`, `qps`, `mappedParamType`, `inParams` | 可选 |
|
|
||||||
| `queryFormParameterList` | Query KV,`fieldPosition=3` |
|
|
||||||
| `headerFormParameterList` | Header KV,`fieldPosition=1` |
|
|
||||||
| `outParameterList` | 出参树 |
|
|
||||||
| `requestBodyParameterList` | **仅下游 Json/Xml**,Body 树 = 映射体 |
|
|
||||||
| `bodyFormParameterList` | **仅下游 FormUrlEncoded**,Body KV |
|
|
||||||
| `mappingBodyParameterList` | **仅下游 FormUrlEncoded**,映射树 |
|
|
||||||
| `inParameterList` | **仅上游**入参树 |
|
|
||||||
|
|
||||||
### 5.2 Body 字段互斥
|
|
||||||
|
|
||||||
| 场景 | 传 | 不传 |
|
|
||||||
|------|-----|------|
|
|
||||||
| 下游 Json/Xml (`contentType` 3/4) | `requestBodyParameterList` | `bodyForm*`、`mappingBody*`、`inParameterList` |
|
|
||||||
| 下游 FormUrlEncoded (`1`) | `bodyFormParameterList` + `mappingBodyParameterList` | `requestBody*`、`inParameterList` |
|
|
||||||
| 上游 | `inParameterList` | `requestBody*`、`bodyForm*`、`mappingBody*` |
|
|
||||||
|
|
||||||
### 5.3 子结构
|
|
||||||
|
|
||||||
**FormParameterInput**(Query / Header / Body 行)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "optionType": 1, "id": 0, "name": "字段名", "value": "$FromMappingBody", "description": "", "fieldPosition": 2 }
|
|
||||||
```
|
|
||||||
|
|
||||||
`fieldPosition`:`1` Header · `2` Body · `3` Query。Form 业务 JSON 字段用 `$FromMappingBody`。
|
|
||||||
|
|
||||||
**ParameterInput**(树节点:requestBody / mappingBody / in / out)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "optionType": 1, "id": 1, "pId": 0, "name": "order", "alias": "order", "type": 3, "isRequired": true, "sort": "1", "paraKind": 0 }
|
|
||||||
```
|
|
||||||
|
|
||||||
`paraKind`:`0` Normal(requestBody、上游 in、出参)· `1` MappingBody(仅 mappingBody 列表)。新增时 `id`/`pId` 需表达父子关系。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5.4 示例
|
|
||||||
|
|
||||||
**下游 · Json**(`contentType: 3`)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"optionType": 1,
|
|
||||||
"isUpStream": false,
|
|
||||||
"serviceProviderId": 5,
|
|
||||||
"name": "创建订单",
|
|
||||||
"requestAddress": "https://api.example.com/order",
|
|
||||||
"requestProtocol": 2,
|
|
||||||
"requestMethod": 2,
|
|
||||||
"contentType": 3,
|
|
||||||
"queryFormParameterList": [
|
|
||||||
{ "optionType": 1, "id": 0, "name": "access_token", "value": "$FromAccount", "fieldPosition": 3 }
|
|
||||||
],
|
|
||||||
"headerFormParameterList": [],
|
|
||||||
"requestBodyParameterList": [
|
|
||||||
{ "optionType": 1, "id": 1, "pId": 0, "name": "orderId", "alias": "orderId", "type": 1, "paraKind": 0 }
|
|
||||||
],
|
|
||||||
"outParameterList": []
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**下游 · FormUrlEncoded**(`contentType: 1`)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"optionType": 3,
|
|
||||||
"isUpStream": false,
|
|
||||||
"serviceProviderId": 5,
|
|
||||||
"id": 1001,
|
|
||||||
"name": "1688回调",
|
|
||||||
"requestAddress": "https://gw.open.1688.com/openapi/http",
|
|
||||||
"requestProtocol": 2,
|
|
||||||
"requestMethod": 2,
|
|
||||||
"contentType": 1,
|
|
||||||
"queryFormParameterList": [
|
|
||||||
{ "optionType": 3, "id": 11, "name": "_aop_timestamp", "value": "$TimeStamp", "description": "ms", "fieldPosition": 3 }
|
|
||||||
],
|
|
||||||
"headerFormParameterList": [],
|
|
||||||
"bodyFormParameterList": [
|
|
||||||
{ "optionType": 3, "id": 10, "name": "notifyBizEventDTO", "value": "$FromMappingBody", "fieldPosition": 2 },
|
|
||||||
{ "optionType": 3, "id": 13, "name": "_aop_signature", "value": "", "fieldPosition": 2 }
|
|
||||||
],
|
|
||||||
"mappingBodyParameterList": [
|
|
||||||
{ "optionType": 3, "id": 1, "pId": 0, "name": "order", "alias": "order", "type": 3, "paraKind": 1 },
|
|
||||||
{ "optionType": 3, "id": 2, "pId": 1, "name": "orderId", "alias": "orderId", "type": 1, "paraKind": 1 }
|
|
||||||
],
|
|
||||||
"outParameterList": []
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**上游**(`isUpStream: true`)
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"optionType": 1,
|
|
||||||
"isUpStream": true,
|
|
||||||
"serviceProviderId": 0,
|
|
||||||
"name": "标准创建订单",
|
|
||||||
"requestAddress": "/api/order/create",
|
|
||||||
"requestProtocol": 2,
|
|
||||||
"requestMethod": 2,
|
|
||||||
"contentType": 3,
|
|
||||||
"queryFormParameterList": [],
|
|
||||||
"headerFormParameterList": [],
|
|
||||||
"inParameterList": [
|
|
||||||
{ "optionType": 1, "id": 1, "pId": 0, "name": "order", "alias": "order", "type": 3, "paraKind": 0 }
|
|
||||||
],
|
|
||||||
"outParameterList": []
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. 转发逻辑(修订)
|
|
||||||
|
|
||||||
### 6.1 映射树来源(InParamTreeList)
|
|
||||||
|
|
||||||
| ContentType | InParamTreeList 来源 |
|
|
||||||
|-------------|----------------------|
|
|
||||||
| Json / Xml | **`requestBodyParameterList`**(整棵树) |
|
|
||||||
| FormUrlEncoded | **`mappingBodyParameterList`** |
|
|
||||||
| 上游 | 系统接口 **inParameterList**(映射配置页不变) |
|
|
||||||
|
|
||||||
### 6.2 HTTP 组装
|
|
||||||
|
|
||||||
| 部分 | 来源 |
|
|
||||||
|------|------|
|
|
||||||
| URL Query | `queryFormParameterList`(+ 服务商 Fixed Query) |
|
|
||||||
| Header | `headerFormParameterList`(+ 服务商 Fixed Header) |
|
|
||||||
| Body Json | `Serialize(requestBodyParameterList` 映射结果 `)` |
|
|
||||||
| Body FormUrlEncoded | 仅 **`bodyFormParameterList`**;其中 `$FromMappingBody` ← 映射结果序列化 |
|
|
||||||
| Body Xml | 同 Json,Xml 序列化 |
|
|
||||||
|
|
||||||
### 6.3 流程对比(两张)
|
|
||||||
|
|
||||||
**Json 下游(无 Mapping Body)**
|
|
||||||
|
|
||||||
```text
|
|
||||||
上游 JSON → Restructure(requestBodyParameterList) → OriginalInterfaceMappedInput
|
|
||||||
→ ReplacePlaceholder(Query/Header form + Fixed)
|
|
||||||
→ SerializationBody(Json) → HTTP Body
|
|
||||||
→ 拼 Query / Header
|
|
||||||
```
|
|
||||||
|
|
||||||
**FormUrlEncoded 下游(有 Mapping Body)**
|
|
||||||
|
|
||||||
```text
|
|
||||||
上游 JSON → Restructure(mappingBodyParameterList) → OriginalInterfaceMappedInput
|
|
||||||
→ ReplacePlaceholder(含 bodyForm 的 $FromMappingBody)
|
|
||||||
→ bodyForm 字典 → HTTP Body
|
|
||||||
→ 拼 Query / Header
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. 前后对比总表(增删改)
|
|
||||||
|
|
||||||
### 7.1 删除了什么
|
|
||||||
|
|
||||||
| 类别 | 内容 |
|
|
||||||
|------|------|
|
|
||||||
| API | 下游 `formParameterList`、下游笼统的 `inParameterList`(拆开后互斥) |
|
|
||||||
| UI | 固定配置 Tab;接口级 Fixed API |
|
|
||||||
| 语义 | 所有下游共用一棵 in 树;Form 无 position;Json 也搞 Mapping Body Tab |
|
|
||||||
| 占位 | 下游表单用 `$FromBody` 表示整段 JSON |
|
|
||||||
|
|
||||||
### 7.2 新增了什么
|
|
||||||
|
|
||||||
| 类别 | 内容 |
|
|
||||||
|------|------|
|
|
||||||
| 表 | `t_parameter_form.FieldPosition`;`t_parameter.ParaKind` |
|
|
||||||
| API | `queryFormParameterList`、`headerFormParameterList`(**全类型共有**) |
|
|
||||||
| API | `bodyFormParameterList`(**仅 Form 类**) |
|
|
||||||
| API | `requestBodyParameterList`(**仅 Json/Xml**,=映射体) |
|
|
||||||
| API | `mappingBodyParameterList`(**仅 Form 类**) |
|
|
||||||
| UI | Header Tab;Form 时 Mapping Body Tab;Json 时 Body=树 |
|
|
||||||
| 占位 | `$FromMappingBody`(**仅 Form KV**) |
|
|
||||||
|
|
||||||
### 7.3 改了什么
|
|
||||||
|
|
||||||
| 项 | 改造前 | 改造后 |
|
|
||||||
|----|--------|--------|
|
|
||||||
| Query | 假 Query(实为 form body) | 真 Query KV,**所有 Content-Type** |
|
|
||||||
| Body Tab | 永远是参数树 | **Json=树**;**Form=KV** |
|
|
||||||
| 映射体 | 永远 in 树 | **Json=Body 树**;**Form=Mapping Body 树** |
|
|
||||||
| 保存 | form + in 混传 | 按 ContentType 传 **互斥** 的 Body 相关列表 |
|
|
||||||
| 映射 SQL | 下游 IsInPara 全量 | Json:RequestBody 树;Form:**ParaKind=MappingBody** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Content-Type 全量对照(改造后)
|
|
||||||
|
|
||||||
| ContentType | queryForm | headerForm | bodyForm | requestBody 树 | mappingBody 树 | 映射目标 | HTTP Body |
|
|
||||||
|-------------|-----------|------------|----------|----------------|----------------|----------|-----------|
|
|
||||||
| **Json** | 可选 | 可选 | **不用** | **必填** | **不用** | requestBody 树 | 序列化该树 |
|
|
||||||
| **Xml** | 可选 | 可选 | **不用** | **必填** | **不用** | requestBody 树 | Xml 序列化 |
|
|
||||||
| **FormUrlEncoded** | 常用 | 常用 | **必填** | **不用** | **必填** | mappingBody 树 | bodyForm 字典 |
|
|
||||||
| **FormData** | 二期 | 二期 | 二期 | **不用** | 二期 | 二期 | 二期 |
|
|
||||||
| **上游 Json** | — | — | — | **inParameterList** | — | in 树 | — |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. 一句话
|
|
||||||
|
|
||||||
| | 改造前 | 改造后 |
|
|
||||||
|---|--------|--------|
|
|
||||||
| 先保存什么 | form + in 混在一起 | **先** Query/Header(通用)+ **再按 Content-Type 存 Body** |
|
|
||||||
| Json | in 树 = 映射 + Body | **requestBody 树 = 映射体**,不要 Mapping Body |
|
|
||||||
| Form | in 树 + form 表 | **bodyForm 传输** + **mappingBody 映射** |
|
|
||||||
| Mapping Body | (之前文档)每个下游都有 | **仅 Form 类需要** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*文档版本:2026-06-02 · 含 SaveInterface 结构与示例(§5)*
|
|
||||||
Loading…
Reference in New Issue
Block a user