# PRD - 性能测试 API 从 curl 自动生成压测任务

> **文档版本**: v1.0
> **创建日期**: 2026-08-19
> **关联模块**: 性能测试
> **优先级**: P3
> **关联需求**: `Docs/PRD/性能测试/需求文档/_PRD_性能测试模块需求文档.md`

---

## 一、背景与目标

### 1.1 背景

当前性能测试模块创建压测任务时，用户需要手动填写以下接口配置：

- HTTP 方法（GET/POST/PUT/DELETE）
- 目标 URL（完整路径）
- 请求头（JSON 格式）
- 请求体（JSON 格式）
- 是否需要登录（Token）
- 是否需要签名（X-RANDOM/X-TIMESTAMP/X-SIGN）

而这些信息在接口调试工具（如 Apifox、Postman 等）复制的 **curl 命令** 中已经完整携带。用户每次新建任务都要把 curl 里的信息逐字转抄到表单，既繁琐又容易出错（如漏掉签名头、URL 拼错）。

用户希望：**粘贴 curl 命令 → 自动解析 → 回填任务表单**，拿接口的 curl 直接生成压测任务，省略手工转抄。

### 1.2 目标

1. **curl 解析**：后端提供解析端点，将 curl 命令结构化（方法、URL、请求头、请求体）
2. **一键回填**：新建任务弹窗提供「从 curl 导入」入口，粘贴后自动回填表单
3. **智能识别认证**：自动识别 `Authorization` 头（置登录开关）与签名头（置签名开关）
4. **友好降级**：不支持的 curl 参数给出友好提示，不阻断回填

### 1.3 范围界定

- ✅ 纯前端解析回填 + 后端辅助解析端点
- ❌ 不联动「另存为接口预设」（预设为 P2 独立功能）
- ❌ 不解析文件上传（`-F`）、Basic Auth（`-u`）等复杂场景（友好提示）

---

## 二、功能范围

### 2.1 核心功能

| 功能 | 描述 | 优先级 |
|------|------|--------|
| curl 解析端点 | 后端 `POST /api/performance/parse-curl` 解析 curl 命令 | P0 |
| 前端导入入口 | 新建任务弹窗「从 curl 导入」按钮 + 粘贴区 | P0 |
| 表单自动回填 | 解析结果映射到任务表单字段 | P0 |
| 认证智能识别 | Authorization 剥离置登录、签名头剥离置签名 | P0 |
| 不支持参数提示 | `-F`/`-u`/`--data-urlencode` 等友好提示 | P1 |

### 2.2 支持的 curl 参数

| curl 参数 | 映射到 | 说明 |
|-----------|--------|------|
| `-X` / `--request` | `method` | HTTP 方法，缺省按是否有 body 推断（有 body 默认 POST，否则 GET） |
| （裸 URL 位置参数） | `target_url` | 第一个不带 `-` 的参数 |
| `-H` / `--header` | `headers` | 多个头合并，逐个处理 `Key: Value` 格式 |
| `-d` / `--data` / `--data-raw` / `--data-binary` / `--data-json` | `body` | 尝试 JSON 解析，失败保留原始字符串 |
| `--compressed` | — | 忽略，不报错 |

### 2.3 认证识别规则

| 检测条件 | 行为 |
|----------|------|
| 存在 `Authorization: Bearer xxx` 头 | 置 `auth_required=True`，并从 headers 中**剥离**该头 |
| 存在 `X-RANDOM` / `X-TIMESTAMP` / `X-SIGN` 头 | 置 `sign_request=True`，并从 headers 中**剥离**这些头 |
| 存在 `Cookie` 头 | **保留**在 headers 中（不剥离） |

### 2.4 不支持的参数（友好提示）

| 参数 | 原因 | 处理 |
|------|------|------|
| `-F` / `--form` | 文件/表单上传 | 提示"暂不支持文件上传" |
| `-u` / `--user` | Basic Auth | 提示"暂不支持 Basic 认证" |
| `--data-urlencode` | URL 编码参数 | 提示"暂不支持 URL 编码参数" |

---

## 三、详细需求

### 3.1 后端解析端点

#### 3.1.1 接口定义

```
POST /api/performance/parse-curl
Content-Type: application/json
```

**请求体**：

```json
{
  "curl_command": "curl -X PUT https://192.168.5.44/meetingV3/api/message/book -H \"Content-Type: application/json\" -H \"X-SIGN: abc\" -d '{\"messageName\": \"test\"}'"
}
```

**响应体**：

```json
{
  "method": "PUT",
  "target_url": "https://192.168.5.44/meetingV3/api/message/book",
  "headers": { "Content-Type": "application/json" },
  "body": { "messageName": "test" },
  "auth_required": false,
  "sign_request": true,
  "cookie": null,
  "errors": []
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `method` | string | 解析出的 HTTP 方法 |
| `target_url` | string | 目标 URL（第一个裸位置参数） |
| `headers` | object | 解析出的请求头（Authorization/签名头已剥离） |
| `body` | any | 请求体（JSON 对象/数组/字符串；bodyTemplate 不填） |
| `auth_required` | bool | 是否检测到 Authorization 头 |
| `sign_request` | bool | 是否检测到签名头 |
| `cookie` | string \| null | Cookie 头的值（已保留在 headers 中） |
| `errors` | array | 不支持的参数提示列表（空数组表示全部支持） |

#### 3.1.2 解析逻辑

实现为纯函数 `parse_curl(curl_command: str) -> CurlParseResult`：

1. 使用 `shlex.split()` 切分 curl 命令（标准库，处理引号嵌套）
2. 遍历参数：
   - `-X` / `--request` 的值 → method
   - 不带 `-` 前缀的裸参数 → target_url（取第一个）
   - `-H` / `--header` 的值 → 按 `Key: Value` 拆分进 headers
   - `-d` / `--data` / `--data-raw` / `--data-binary` / `--data-json` 的值 → body
   - `-F` / `--form` → errors 追加提示
   - `-u` / `--user` → errors 追加提示
   - `--data-urlencode` → errors 追加提示
   - `--compressed` → 忽略
3. 方法推断：若未显式指定 `-X`，有 body 默认 `POST`，无 body 默认 `GET`
4. 认证识别：遍历 headers，检测 `Authorization` / `X-RANDOM` / `X-TIMESTAMP` / `X-SIGN` 键（大小写不敏感），按 2.3 规则剥离/置开关
5. body 解析：尝试 `json.loads()`，成功返回解析后的对象，失败保留原始字符串
6. 同一键的多个 header 值：用 `; ` 拼接合并

#### 3.1.3 边界情况

| 场景 | 行为 |
|------|------|
| curl 命令为空 | 返回 400，错误信息"curl 命令不能为空" |
| 命令无法解析（无 URL） | 返回 400，错误信息"未识别到目标 URL" |
| 多个 `-d` | 按 `&` 拼接后尝试 JSON 解析（与 curl 行为一致） |
| header 值无冒号 | 忽略该 header，不报错 |
| URL 是第一个位置参数但中间出现 | 取第一个裸参数作为 URL |

### 3.2 前端交互

#### 3.2.1 入口

新建任务弹窗（`TaskList.vue`）工具栏新增「从 curl 导入」按钮。

#### 3.2.2 交互流程

1. 点击「从 curl 导入」→ 弹出 curl 导入对话框
2. 对话框中粘贴 curl 命令到 textarea
3. 点击「解析导入」→ 调用 `POST /api/performance/parse-curl`
4. 解析成功后关闭对话框并回填表单：
   - `method` → 表单 method
   - `target_url` → 表单 targetUrl（必填校验）
   - `headers` → 表单 headers（JSON 字符串格式化 `JSON.stringify(obj, null, 2)`）
   - `body` → 表单 body（JSON 字符串格式化）
   - `auth_required` → 表单 authRequired
   - `sign_request` → 表单 signRequest
   - 清空 `presetId`，解除接口字段 disabled 状态
5. 若有 `errors` 列表，回填后弹出 `ElMessage.warning` 逐条提示（不阻断）

#### 3.2.3 表单联动

- 回填后若之前选择了接口预设（`presetId` 非空），清空预设选择，恢复接口字段可编辑（回填值与预设无关）
- `authRequired`、`signRequest` 均为开关控件，直接置为解析结果

### 3.3 无需后端建表

本功能为**纯解析能力**，不新增数据库表、不新增模型字段，任务创建/存储链路完全不变。

---

## 四、非功能需求

### 4.1 兼容性

- 全部使用 Python 标准库（`shlex`、`json`），不新增第三方依赖
- 纯函数设计，解析逻辑与 HTTP/DB 解耦，便于单元测试
- 前端回填后用户仍可手动修改所有字段（回填只是预填，不锁定）

### 4.2 可靠性

- 解析器对异常输入不抛异常，未知/不支持参数收集到 `errors` 列表
- `-X` 与 body 推断冲突时以 `-X` 显式指定为准

### 4.3 约束

- curl 命令最长 10000 字符（前后端同步校验）
- headers 最多解析 50 个

---

## 五、影响范围

### 5.1 新增文件

| 文件 | 说明 |
|------|------|
| `backend/app/utils/curl_parser.py` | curl 解析纯函数模块 |

### 5.2 修改文件

| 文件 | 变更 |
|------|------|
| `backend/app/schemas/performance.py` | 新增 `CurlParseRequest` / `CurlParseResponse` |
| `backend/app/routers/performance.py` | 新增 `POST /parse-curl` 路由 |
| `frontend/src/api/performance.ts` | 新增 `parseCurl()` API 封装 |
| `frontend/src/types/performance.ts` | 新增 `CurlParseResult` 类型 |
| `frontend/src/views/performance/TaskList.vue` | 新增「从 curl 导入」按钮 + 对话框 + 回填逻辑 |

---

## 六、验收标准

| # | 验收项 | 验证方式 |
|---|--------|---------|
| 1 | 标准 POST curl 解析 | `curl -X POST https://example.com/api -H "Content-Type: application/json" -d '{"key":"val"}'` → method=POST、URL、headers、body 均正确 |
| 2 | GET 无 body 推断 | 无 `-X` 无 body → method=GET |
| 3 | Authorization 剥离 | 解析后 headers 不含 Authorization，authRequired=true |
| 4 | 签名头剥离 | 解析后 headers 不含 X-SIGN 等，signRequest=true |
| 5 | Cookie 保留 | 解析后 headers 含 Cookie |
| 6 | 不支持参数提示 | `-F` 类参数 → errors 列表含提示，其余字段正常解析 |
| 7 | 前端回填 | 粘贴 curl → 解析 → 表单 method/URL/headers/body/开关全部回填 |
| 8 | 预设解除 | 回填后 presetId 清空、接口字段可编辑 |
| 9 | 保存并创建 | 回填后直接保存，成功创建任务 |
| 10 | 空命令错误 | 空 curl → 后端 400 错误提示 |

---

*本文档为从 curl 自动生成压测任务功能的需求定义，后续将输出计划执行文档用于指导开发。*