# 【新增接口·管理后台】图标库 新增 parse-svg-text（支持第三方图标库直传 SVG 字符串校验）

> **PR**: #3437 | **关联工单**: #3434
> **服务**: hl-user-service | **更新时间**: 2026-06-04
>
> **存放目录**: `changelogs-v2/2026-06/`
> **影响范围**: 管理后台「图标库」图标新增/编辑页——新增图标的「来源」除「上传 SVG 文件」外，新增「从第三方图标库选取」路径

---

## ⚠️ 关键说明

1. **新输入路径**：前端反馈，除了上传 `.svg` 文件，运营还可以从前端集成的**第三方图标库**（iconfont / 图标组件库等）直接选取图标，此时前端**已经拿到 SVG 字符串**，无需"上传文件 → 后端解析"这一步。

2. **两条保存路径都支持，二选一**：

   | 路径 | 调用 | 适用 |
   |---|---|---|
   | A. 直接保存 | `POST /admin/icon/item`（`svgContent` 直接传字符串） | 第三方库字符串**本就能直接保存**——保存接口的 `svgContent` 一直是字符串字段，且后端保存时第一步即做同款安全校验 |
   | B. 先预校验再保存（**推荐**） | `POST /admin/icon/parse-svg-text` 预校验 → 填表单 → `POST /admin/icon/item` 保存 | 与「上传文件」路径（`parse-svg` → 保存）UX 对称，**错误早暴露**：含 `<script>`/DOCTYPE 等浏览器能渲染、后端会拒的内容，选取后立即报错，不必等填完整张表单点保存才发现 |

3. **安全口径完全一致**：`parse-svg-text` 与文件路径 `parse-svg`、以及保存接口共用**同一套**服务端校验（XXE-safe 解析 + 拒 `<script>`/`<foreignObject>`/`on*` 事件属性/`javascript:` 外链 + ≤256KB）。`parse-svg-text` **仅校验、不落库**；落库仍走保存接口（保存时二次校验，纵深防御）。前端内联渲染 SVG 时**仍建议先做一次 sanitize**。

4. 本次**纯加性**：不改动任何已有端点（`parse-svg` / `item` / 查询等契约全部不变）。

---

## 1. 接口背景

图标库新增图标原流程（上传文件）：

```
上传 .svg 文件 → POST /admin/icon/parse-svg（解析+校验，返回字符串）→ 回填表单 → POST /admin/icon/item（保存）
```

新增「第三方库选取」路径，前端已持有字符串，对称流程：

```
第三方库选取（拿到 SVG 字符串）→ POST /admin/icon/parse-svg-text（校验，返回字符串）→ 回填表单 → POST /admin/icon/item（保存）
```

---

## 2. 变更清单

| # | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|----------|------|
| 1 | POST | `/admin/icon/parse-svg-text` | **新增** | 校验前端直传的 SVG 字符串（来自第三方库），仅校验不落库 |

> 网关路由 `/admin/icon/**` 已是通配，本端点自动覆盖，无需前端额外处理路由。

---

## 3. 接口详情

### 3.1 校验前端直传的 SVG 字符串

**POST** `/admin/icon/parse-svg-text`

- **使用场景**：从第三方图标库选取图标（已是字符串）后，保存前做合法性 + 安全校验
- **认证**：管理后台 JWT
- **幂等**：是（仅校验，不落库）

**Body 入参**（`IconSvgParseTextReqVO`）：

| 字段 | 类型 | 必填 | 校验 | 说明 |
|---|---|---|---|---|
| `svgContent` | string | ✅ | `@NotBlank` + `@Size(max=262144)` | 第三方库选取的原始 SVG 字符串（UTF-8 文本） |

**出参**：`Result<IconSvgParseRespVO>`（与 `parse-svg` 复用同一响应 VO）

| 字段 | 类型 | 说明 |
|---|---|---|
| `svgContent` | string | 校验通过的 SVG 字符串（原样回填保存表单） |
| `fileName` | string | **恒为 `null`**（非文件来源，仅文件上传路径才有值） |
| `size` | long | 内容**字节数（UTF-8 编码）**，非字符数 |

**典型示例 请求**：
```bash
curl -X POST "https://api.test.1814.love:9443/admin/icon/parse-svg-text" \
  -H "Authorization: Bearer <adminToken>" \
  -H "Content-Type: application/json" \
  -d '{"svgContent":"<svg viewBox=\"0 0 24 24\"><path d=\"M0 0h24v24H0z\"/></svg>"}'
```

**典型示例 响应**（测试服实测）：
```json
{
  "code": 200,
  "data": {
    "svgContent": "<svg viewBox=\"0 0 24 24\"><path d=\"M0 0h24v24H0z\"/></svg>",
    "fileName": null,
    "size": 56
  },
  "message": "成功"
}
```

**异常 响应**（SVG 含脚本/事件/外链，测试服实测）：
```json
{ "code": 210757, "message": "SVG 含不安全内容(脚本/事件/外链)，请清理后重试", "data": null }
```

**异常 响应**（svgContent 为空/纯空白，@NotBlank 拦截）：
```json
{ "code": 400, "message": "SVG 内容不能为空", "data": null }
```

---

### 3.2 保存图标（已有接口，未变，此处仅提示第三方库路径如何用）

**POST** `/admin/icon/item`

第三方库选取的字符串可**直接**作为 `svgContent` 传入保存，无需先上传成文件。保存接口本就对 `svgContent` 做同款安全校验（见 §6 错误码）。完整字段契约见图标库模块首推 changelog `03_3390_图标库模块...` §3.6，本次未改动。

---

## 4. 前端动作（mmg）

1. **图标新增/编辑页加"来源"选择**：现有「上传 SVG 文件」之外，加「从第三方图标库选取」。
2. **第三方库选取后（推荐路径 B）**：拿到 SVG 字符串 → 调 `POST /admin/icon/parse-svg-text` 预校验 → 成功则用返回的 `svgContent` 回填表单（同上传文件路径的回填逻辑）→ 失败则按 §6 错误码提示用户更换图标。
3. **或直接保存（路径 A）**：若不想加预校验步骤，可把第三方库字符串直接放进 `POST /admin/icon/item` 的 `svgContent`，保存接口会做同款校验并返回对应错误码。
4. **渲染仍建议 sanitize**：后端已拒明显恶意内容，前端内联渲染（`v-html`/`innerHTML`）时再做一次 sanitize 作纵深防御。

---

## 5. 枚举 / 数据字典

无新增枚举。本端点不涉及状态/类型字段。

---

## 6. 错误码

| code | 含义 | 触发条件 | 涉及接口 |
|---|---|---|---|
| 400 | 参数校验失败 | `svgContent` 为空/纯空白（`@NotBlank`）或超 `@Size(262144)` | §3.1 |
| 401 | 未登录 | admin JWT 无效或缺失 | §3.1 |
| **210754** | SVG 内容不合法 | 非合法 XML 或根元素不是 `<svg>` | §3.1 §3.2 |
| **210755** | SVG 内容过大 | 超过 256KB（按 UTF-8 字节） | §3.1 §3.2 |
| **210757** | SVG 含不安全内容 | 含 `<script>` / `<foreignObject>` / `on*` 事件 / `javascript:` 外链 | §3.1 §3.2 |

> `parse-svg-text` 的错误码是文件路径 `parse-svg` 的子集（无 `210753`「文件为空」/`210756`「文件读取失败」——这两个仅文件上传场景有；字符串为空由 `@NotBlank` 在网关层返 400）。错误码段位 210700-210799 归属图标库模块。

---

## 7. 验证（测试服实测，已通过）

| 用例 | 输入 | 结果 |
|---|---|---|
| 合法字符串 | 标准 SVG | http200 / code200，`svgContent` 回显、`fileName=null`、`size=56` |
| 含 `<script>` | 带脚本的 SVG | http200 / **code210757** 拒 |
| 空白串 | `"   "` | http200 / **code400** SVG内容不能为空 |
| 中文 SVG | 含 `<title>晴天</title>` | http200 / code200，`size=83` > 字符数 79（证明按 UTF-8 字节计） |

- 单测 `IconItemServiceTest` 36 全绿（含 script/事件/外链/foreignObject/超限/UTF-8 字节数等正反路径）
- hl-user-service 双实例（8081 + 8181）均已部署新代码、health UP

---

## 8. 影响评估

- **是否破坏向后兼容**：否（纯新增端点，无任何已有接口改动）
- **前端是否必须同步上线**：是（新输入路径，前端按 §4 接入「第三方库选取」）
- **影响已有数据**：无

---

## 9. 关联 / 联系人

- **本次 PR**：#3437（Closes #3434）
- **图标库模块首推 changelog**：`03_3390_图标库模块-新增接口-管理后台+小程序.md`（含分类/图标/上传解析全量契约）
- **后端负责人**：@wx
- **前端对接（管理后台）**：mmg
