hl-api-changelog/changelogs-v2/2026-06/04_3434_图标库-第三方库直传SVG字符串校验-管理后台.md
API Changelog Bot fca672aaf1 feat(图标库): 支持第三方库直传 SVG 字符串校验(新增 parse-svg-text, PR #3437)
图标新增除上传文件外,前端可从第三方图标库直接选取(已是字符串)。
新增 POST /admin/icon/parse-svg-text 做入库前预校验(同 parse-svg 安全口径);
第三方库字符串也可直接走 POST /admin/icon/item 保存(保存接口本就同款校验)。
测试服实测通过(合法200/script拒210757/空白400/中文按字节计)。
2026-06-04 11:04:04 +08:00

176 行
7.9 KiB
Markdown

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

# 【新增接口·管理后台】图标库 新增 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**#3437Closes #3434
- **图标库模块首推 changelog**`03_3390_图标库模块-新增接口-管理后台+小程序.md`(含分类/图标/上传解析全量契约)
- **后端负责人**@wx
- **前端对接(管理后台)**mmg