# 编辑HTTP服务

`POST` `/api/agent/finx/updateHttpService`

全量替换指定 HTTP 类型 Finx 服务的配置（名称、展示名、Logo、描述、parameterSchema、httpConfig）。允许修改 serviceName 并会做唯一性校验（排除自身）。

**更新语义**：httpConfig 整体覆盖原配置，auth 也按请求内容整体保存；值为脱敏形式（含 `***`）的凭证字段会自动回填库中原值，星号不会落库。因此建议先调用 getServiceDetail 拿到当前完整配置（含 httpConfig.serviceEndpoint），在其上修改后回传，避免字段丢失。

**注意**：本接口不会做连通性测试；且切勿传入 MCP 服务 ID，后端会按服务类型校验，类型不匹配直接报错。用户各自的凭证仍由 saveAuthCredential 独立管理。

## 请求参数

### 请求体（JSON）

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| agentId | integer | 是 | 智能体ID，需与该服务归属的智能体一致，否则报错 |
| id | integer | 是 | 服务ID，由 listServices / getServiceDetail 返回；必须是 HTTP 类型服务的 ID，传入 MCP 服务 ID 会因类型不匹配直接报错 |
| serviceName | string | 是 | 服务标识名，创建后作为 finx 命令中调用该服务的名字。必须以英文字母或下划线开头，只能包含字母、数字、下划线和连字符，长度不超过 64；在同一智能体内以及与平台全局服务之间都不能重名，重名会直接报错。允许修改，会做唯一性校验（排除自身） |
| displayName | string | 否 | 服务中文名（前端展示用，可为空，为空时展示服务标识名），长度不超过64 |
| logoUrl | string | 否 | 服务Logo URL（前端展示用，可为空），长度不超过512 |
| description | string | 否 | 服务描述，长度不超过 512。**智能体依赖这段描述判断什么场景该调用该服务**，请写清能力范围、覆盖的数据品类与适用问题场景，描述越准确调用时机越准 |
| parameterSchema | string | 否 | **参数Schema（JSON字符串，不是JSON对象）**
- 内容为标准 JSON Schema，需作为**字符串**传递（注意转义内部的双引号）；保存时会做合法性校验，不合法直接报错
- 作用：告诉智能体调用该接口时要传哪些参数。每个属性的 description 直接影响模型选参的准确度，务必写清楚含义与取值示例
- HTTP 类型的工具 / serviceEndpoint 建议填写；MCP 类型不需要（工具入参由 MCP Server 动态提供）
- Schema 内容示例：`{"type":"object","required":["query"],"properties":{"query":{"type":"string","description":"自然语言查询，如：宁德时代最新研报"},"limit":{"type":"integer","description":"返回条数，默认10"}}}`
- 本字段描述的是 httpConfig.serviceEndpoint 的入参，仅在配置了 serviceEndpoint 时有意义；服务下各工具的入参用 updateTool 单独维护 |
| httpConfig | object | 是 | 整体覆盖原配置。建议先调用 getServiceDetail 拿到当前完整配置（含 serviceEndpoint），在其上修改后回传，避免字段丢失。

**HTTP服务配置（JSON对象）**
- baseUrl：服务基础地址（必填），与工具的 path 拼接成最终请求地址，如 `https://api.example.com` + `/api/data/query`
- auth：服务级鉴权配置，字段说明见下方；该服务下的工具默认继承服务级鉴权（工具端点的 inheritAuth 默认 true）
- serviceEndpoint：服务自身可直接调用的端点（选填）。只有「服务本身就是一个可调用接口」时才填；若该服务有多个接口，请把每个接口作为一个工具用 createTool 单独创建

**保存时的行为**
- 与 MCP 不同，创建/编辑 HTTP 服务**不会**发起连通性测试，保存成功不代表地址与凭证可用，建议随后用 execute 接口实际调用一次验证
- parameterSchema 若传了，会做 JSON Schema 合法性校验，不合法直接报错

**完整示例**
- 仅服务级配置（各接口另行用 createTool 创建）：`{"baseUrl":"https://api.example.com","auth":{"type":"CUSTOM","customHeaders":{"em_api_key":"xxx"}}}`
- 服务本身即一个端点：`{"baseUrl":"https://api.example.com","auth":{"type":"BEARER","credential":"my-token"},"serviceEndpoint":{"method":"POST","path":"/api/query","contentType":"application/json","timeout":30000}}`
- 服务端点为 SSE 流式：`{"baseUrl":"https://api.example.com","serviceEndpoint":{"method":"POST","path":"/api/chat/stream","contentType":"application/json","streaming":true,"resultEventName":"tool_observation"}}`

**serviceEndpoint 的字段说明**
- method：HTTP 方法（必填），如 GET / POST / PUT / DELETE
- path：相对 baseUrl 的请求路径（必填），支持 `{变量}` 占位，如 `/api/stock/{symbol}`
- contentType：请求体 Content-Type（选填），如 `application/json`
- timeout：超时时间（毫秒，选填），不传时使用服务默认值
- queryParams：字段名数组（选填），声明哪些入参通过 URL 查询参数传递，未声明的入参走请求体
- inheritAuth：是否继承服务级鉴权（选填，默认 true）
- auth：端点级鉴权（选填），仅当 inheritAuth=false、该接口使用独立凭证时才需要，字段说明见下方
- streaming：是否以 SSE（text/event-stream）方式消费该端点（选填，默认 false）
- resultEventName：SSE 流中作为「模型观察结果」的保留事件名（选填，默认 `tool_observation`）。streaming=true 时，中间帧实时透传给终端界面，只有该事件名对应帧的 data 会作为模型观察结果；流中没有该事件时回退取最后一帧

**端点示例**
- 普通 JSON 接口：`{"method":"POST","path":"/api/data/query","contentType":"application/json","timeout":30000,"queryParams":["page","size"]}`
- GET 接口（参数走 URL）：`{"method":"GET","path":"/api/stock/{symbol}","queryParams":["period"]}`
- SSE 流式接口：`{"method":"POST","path":"/api/chat/stream","contentType":"application/json","streaming":true,"resultEventName":"tool_observation"}`

**auth（鉴权配置，选填。不传或 type=NONE 表示该服务无需鉴权）**
- type：鉴权类型。**请求侧键名是 `type`；响应侧（getServiceDetail、getAuthSchema）回显时叫 `authType`，两者不要混用**。可选值：
  - NONE：无需认证
  - API_KEY：API 密钥放在请求头
  - BEARER：Bearer 令牌
  - BASIC：HTTP Basic 认证
  - CUSTOM：一个或多个自定义请求头
  - CUSTOM_HTTP_TOKEN：先调用一个 HTTP 接口动态换取令牌
  - OAUTH：OAuth 2.1 按用户授权（平台预置数据源专用，见下文）
- headerName：API_KEY 使用的请求头名，不传时默认 `X-API-Key`
- tokenPrefix：BEARER 使用的令牌前缀，不传时默认 `Bearer`（BASIC 固定使用 `Basic`，此字段对它无效）
- credential：主凭证值，API_KEY / BEARER / BASIC 使用。BEARER 只填令牌本身、**不要带 `Bearer ` 前缀**；BASIC 填 `base64(用户名:密码)` 的结果
- customHeaders：自定义请求头键值对，CUSTOM 使用，运行时按原样作为请求头发送
- queryParams：URL 查询参数键值对，**可与任意 type 叠加**，运行时拼接到请求 URL 上（如 `?apiKey=xxx`）
- requireUserProvided：凭证由谁提供，不传时默认 false
  - false（平台统一凭证）：在 auth 里直接写真实凭证值，该服务的所有用户共用这一份凭证
  - true（用户各自提供）：auth 只作为模板，仅声明字段名、凭证值留空串；每个用户后续通过 saveAuthCredential 提交自己的凭证
- tokenFetchConfig：动态换取令牌的配置，仅 type=CUSTOM_HTTP_TOKEN 时需要，子字段：
  - method：换取令牌的请求方法，不传时默认 POST
  - url：换取令牌的接口地址（必填）
  - headers：换取令牌时携带的请求头，客户端凭证放在这里（如 `{"Authorization":"Basic xxx"}`）
  - body：换取令牌的请求体字符串（如 `grant_type=client_credentials`）
  - tokenField：从响应 JSON 中取令牌的字段名，不传时默认 `access_token`
  - expiresInField：从响应 JSON 中取有效期（秒）的字段名，不传时默认 `expires_in`
  - targetHeaderName：把令牌注入业务请求时使用的请求头名，不传时默认 `Authorization`
  - targetTokenPrefix：注入令牌时使用的前缀，不传时默认 `Bearer`
  - refreshBufferSeconds：在令牌到期前多少秒主动刷新，不传时默认 60

**各 type 的 auth 写法示例**
- NONE：`{"type":"NONE"}`
- API_KEY（默认请求头 X-API-Key）：`{"type":"API_KEY","credential":"sk-abcdef123456"}`
- API_KEY（自定义请求头名）：`{"type":"API_KEY","headerName":"X-Custom-Key","credential":"sk-abcdef123456"}`
- BEARER：`{"type":"BEARER","credential":"eyJhbGciOiJIUzI1NiJ9.payload.sig"}`
- BASIC：`{"type":"BASIC","credential":"dXNlcjpwYXNz"}`（`dXNlcjpwYXNz` 即 base64 编码后的 `user:pass`）
- CUSTOM（多个自定义头）：`{"type":"CUSTOM","customHeaders":{"X-App-Id":"123","X-App-Secret":"abc"}}`
- CUSTOM_HTTP_TOKEN：`{"type":"CUSTOM_HTTP_TOKEN","tokenFetchConfig":{"method":"POST","url":"https://auth.example.com/oauth2/token","headers":{"Authorization":"Basic dXNlcjpwYXNz","Content-Type":"application/x-www-form-urlencoded"},"body":"grant_type=client_credentials","tokenField":"access_token","expiresInField":"expires_in","targetHeaderName":"Authorization","targetTokenPrefix":"Bearer","refreshBufferSeconds":60}}`
- 用户各自提供凭证（只声明字段名、值留空）：`{"type":"CUSTOM","customHeaders":{"X-App-Secret":""},"requireUserProvided":true}`
- 鉴权信息放 URL 参数（与 BEARER 叠加）：`{"type":"BEARER","credential":"my-token","queryParams":{"appId":"123"}}`
- OAUTH：仅用于平台预置的「按用户授权」数据源，需平台侧先完成 OAuth 客户端注册，通过本接口自助创建服务时暂不支持自行配置，如有此类需求请联系平台

**凭证安全**
- credential、customHeaders 与 queryParams 的值落库前会加密存储；getServiceDetail 只回显含 `***` 的脱敏值，不会返回明文
- 编辑服务时把脱敏值原样回传即表示「保留原值」，星号不会被写入库；要真正修改就传新的明文值

**编辑时 auth 的处理（本接口）**
- httpConfig 整体覆盖原配置，auth 也按请求内容整体保存：customHeaders / queryParams 的最终 key 集合完全以请求为准，未出现的 key 即被删除（本接口不支持 customHeaderKeys / queryParamKeys）
- 唯一例外：值为脱敏形式（含 `***`）的字段会自动回填库中原值，星号不会落库
- 因此建议先调用 getServiceDetail 取到完整配置，在其上修改后整体回传，避免字段丢失 |

## 响应

### 200

| 参数名 | 类型 | 说明 |
|--------|------|------|
| httpStatusCode | integer | HTTP状态码 |
| message | string | 响应消息 |
| data | object | 响应数据 |
| success | boolean | 是否成功 |
| requestId | string | 上游请求ID，用于跨系统链路追踪排查问题 |
| errCode | string | 上游错误码，前端可据此做特殊UI处理 |

### 400

| 参数名 | 类型 | 说明 |
|--------|------|------|
| httpStatusCode | integer | HTTP状态码 |
| message | string | 响应消息 |
| data | object | 响应数据 |
| success | boolean | 是否成功 |
| requestId | string | 上游请求ID，用于跨系统链路追踪排查问题 |
| errCode | string | 上游错误码，前端可据此做特殊UI处理 |

### 500

| 参数名 | 类型 | 说明 |
|--------|------|------|
| httpStatusCode | integer | HTTP状态码 |
| message | string | 响应消息 |
| data | object | 响应数据 |
| success | boolean | 是否成功 |
| requestId | string | 上游请求ID，用于跨系统链路追踪排查问题 |
| errCode | string | 上游错误码，前端可据此做特殊UI处理 |

