# 演练场增强功能实现总结
## 项目日期
2026年1月18日
## 功能概述
本次实现为NetDisk Fast Download项目的演练场(Playground)增加了以下核心功能:
### 1. 编辑器UI增强
- **文件导入功能** - 支持直接导入本地JS/Python/TXT文件
- **原生粘贴支持** - 增强粘贴操作,支持多行代码粘贴,优化移动端体验
### 2. 网络请求安全拦截
- **requests_guard猴子补丁** - 完整的请求拦截和审计日志系统
- **Python代码预处理** - 在运行时自动检测并注入安全补丁
- **实时日志反馈** - 演练场控制台显示安全拦截操作
---
## 详细实现
### 一、演练场编辑器UI增强 (web-front)
#### 1.1 文件导入功能
**位置**: `web-front/src/views/Playground.vue`
**新增组件**:
```vue
```
**新增菜单项**:
```vue
导入文件
```
**实现的方法**:
```javascript
// 触发文件选择对话框
const importFile = () => {
if (fileImportInput.value) {
fileImportInput.value.click();
}
};
// 处理文件导入
const handleFileImport = async (event) => {
const file = event.target.files?.[0];
if (!file) return;
try {
const fileContent = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.onerror = () => reject(new Error('文件读取失败'));
reader.readAsText(file, 'UTF-8');
});
if (activeFile.value) {
activeFile.value.content = fileContent;
activeFile.value.modified = true;
activeFile.value.name = file.name;
// 根据文件扩展名识别语言
const ext = file.name.split('.').pop().toLowerCase();
if (ext === 'py') {
activeFile.value.language = 'python';
} else if (ext === 'js' || ext === 'txt') {
activeFile.value.language = 'javascript';
}
saveAllFilesToStorage();
ElMessage.success(`文件"${file.name}"已导入,大小:${(file.size / 1024).toFixed(2)}KB`);
}
} catch (error) {
ElMessage.error('导入失败: ' + error.message);
}
// 重置input以允许再次选择同一文件
if (fileImportInput.value) {
fileImportInput.value.value = '';
}
};
```
**特点**:
- 支持 `.js`, `.py`, `.txt` 文件格式
- 自动识别文件语言并设置编辑器模式
- 文件大小提示
- 保存到LocalStorage
---
#### 1.2 原生粘贴支持增强
**位置**: `web-front/src/views/Playground.vue`
**改进点**:
1. **多行粘贴支持** - 正确处理多行代码粘贴
2. **移动端优化** - 处理输入法逐行输入问题
3. **错误处理** - 友好的权限和错误提示
```javascript
const pasteCode = async () => {
try {
const text = await navigator.clipboard.readText();
if (!text) {
ElMessage.warning('剪贴板为空');
return;
}
if (editorRef.value && editorRef.value.getEditor) {
const editor = editorRef.value.getEditor();
if (editor) {
const model = editor.getModel();
if (!model) {
ElMessage.error('编辑器未就绪');
return;
}
// 获取当前选择范围,如果没有选择则使用光标位置
const selection = editor.getSelection();
const range = selection || new (window.monaco?.Range || editor.getModel().constructor.Range)(1, 1, 1, 1);
// 使用executeEdits执行粘贴操作,支持一次多行粘贴
const edits = [{
range: range,
text: text,
forceMoveMarkers: true
}];
editor.executeEdits('paste-command', edits, [(selection || range)]);
editor.focus();
const lineCount = text.split('\n').length;
ElMessage.success(`已粘贴 ${lineCount} 行内容`);
}
} else {
ElMessage.error('编辑器未加载');
}
} catch (error) {
if (error.name === 'NotAllowedError') {
ElMessage.warning('粘贴权限被拒绝,请使用 Ctrl+V 快捷键');
} else {
console.error('粘贴失败:', error);
ElMessage.error('粘贴失败: ' + (error.message || '请使用 Ctrl+V'));
}
}
};
```
**特点**:
- 处理粘贴权限问题
- 显示粘贴行数
- 支持选区替换和光标位置插入
---
### 二、网络请求安全拦截系统
#### 2.1 requests_guard.py 猴子补丁模块
**位置**: `parser/src/main/resources/requests_guard.py`
**核心功能**:
1. **IP地址验证**
```python
PRIVATE_NETS = [
"127.0.0.0/8", # 本地回环
"10.0.0.0/8", # A 类私网
"172.16.0.0/12", # B 类私网
"192.168.0.0/16", # C 类私网
"0.0.0.0/8", # 0.x.x.x
"169.254.0.0/16", # Link-local
"224.0.0.0/4", # 多播地址
"240.0.0.0/4", # 预留地址
]
```
2. **危险端口检测**
```python
DANGEROUS_PORTS = [
22, 25, 53, 3306, 5432, 6379, # 常见网络服务
8000, 8001, 8080, 8888, # 开发服务器端口
27017, # MongoDB
]
```
3. **请求拦截与审计日志**
```
[2026-01-18 10:15:30.123] [Guard-ALLOW] GET https://example.com/api/data
[2026-01-18 10:15:35.456] [Guard-BLOCK] POST https://127.0.0.1:8080/api - 本地地址
[2026-01-18 10:15:40.789] [Guard-BLOCK] GET https://192.168.1.10/api - 私网地址
```
4. **支持的网络库**
- `requests` - 完整支持
- `urllib` - urllib.request.urlopen 包装
- 可扩展支持 httpx、aiohttp 等
5. **安全检查点**
- URL 格式验证
- 协议检查(仅允许 http/https)
- 本地地址检测(localhost, 127.0.0.1, ::1)
- 私网地址检测(CIDR 检查)
- 危险端口检测
- DNS 解析结果验证
---
#### 2.2 PyCodePreprocessor Java类
**位置**: `parser/src/main/java/cn/qaiu/parser/custompy/PyCodePreprocessor.java`
**核心职责**:
1. **代码分析** - 检测代码中的网络请求库导入
```java
// 检测的导入模式
IMPORT_REQUESTS // import requests 或 from requests
IMPORT_URLLIB // import urllib 或 from urllib
IMPORT_HTTPX // import httpx 或 from httpx
IMPORT_AIOHTTP // import aiohttp 或 from aiohttp
IMPORT_SOCKET // import socket 或 from socket
```
2. **猴子补丁注入** - 在代码执行前动态注入补丁
```
原始代码:
"""模块文档"""
import requests
def parse():
...
注入后的代码:
"""模块文档"""
# ===== 自动注入的网络请求安全补丁 (由 PyCodePreprocessor 生成) =====
[requests_guard.py 完整内容]
# ===== 安全补丁结束 =====
import requests
def parse():
...
```
3. **日志生成** - 为演练场控制台生成预处理信息
```
✓ 网络请求安全拦截已启用 (检测到: requests, urllib) | 已动态注入 requests_guard 猴子补丁
```
**实现细节**:
```java
public static PyPreprocessResult preprocess(String originalCode) {
if (originalCode == null || originalCode.trim().isEmpty()) {
return new PyPreprocessResult(originalCode, false, null, "代码为空,无需预处理");
}
// 检测网络请求库
NetworkLibraryDetection detection = detectNetworkLibraries(originalCode);
if (detection.hasAnyNetworkLibrary()) {
// 加载猴子补丁代码
String patchCode = loadRequestsGuardPatch();
if (patchCode != null && !patchCode.isEmpty()) {
// 在代码头部注入补丁
String preprocessedCode = injectPatch(originalCode, patchCode);
String logMessage = String.format(
"✓ 网络请求安全拦截已启用 (检测到: %s) | 已动态注入 requests_guard 猴子补丁",
detection.getDetectedLibrariesAsString()
);
return new PyPreprocessResult(
preprocessedCode,
true,
detection.getDetectedLibraries(),
logMessage
);
}
}
return new PyPreprocessResult(originalCode, false, null,
"ℹ 代码中未检测到网络请求库,不需要注入安全拦截补丁");
}
```
---
#### 2.3 PyPlaygroundExecutor集成
**位置**: `parser/src/main/java/cn/qaiu/parser/custompy/PyPlaygroundExecutor.java`
**集成点**:
在 `executeParseAsync()`、`executeParseFileListAsync()` 和 `executeParseByIdAsync()` 方法中添加代码预处理:
```java
// Python代码预处理 - 检测并注入猴子补丁
PyCodePreprocessor.PyPreprocessResult preprocessResult = PyCodePreprocessor.preprocess(pyCode);
playgroundLogger.infoJava(preprocessResult.getLogMessage());
String codeToExecute = preprocessResult.getProcessedCode();
// 然后执行预处理后的代码
context.eval("python", codeToExecute);
```
**日志流程**:
1. 预处理时生成日志信息
2. 通过 `playgroundLogger.infoJava()` 添加到日志列表
3. 日志包含在 API 响应中返回给前端
4. 前端在演练场控制台中显示
---
### 三、演练场控制台日志显示
#### 3.1 前端日志显示增强
**位置**: `web-front/src/views/Playground.vue`
**日志来源标记**:
```vue
[{{ log.source === 'java' ? 'JAVA' : (log.source === 'JS' ? 'JS' : 'PYTHON') }}]
```
**CSS样式分类**:
```css
/* JavaScript日志 - 绿色主题 */
.console-js-source {
border-left-color: var(--el-color-success) !important;
background: var(--el-color-success-light-9) !important;
}
/* Java日志(包括预处理日志)- 橙色主题 */
.console-java-source {
border-left-color: var(--el-color-warning) !important;
background: var(--el-color-warning-light-9) !important;
}
/* Python日志 - 蓝色主题 */
.console-python-source {
border-left-color: var(--el-color-info) !important;
background: var(--el-color-info-light-9) !important;
}
/* 源标记样式 */
.console-source-tag {
display: inline-block;
color: white;
font-size: 10px;
padding: 3px 8px;
border-radius: 10px;
margin-right: 8px;
font-weight: 600;
flex-shrink: 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.console-source-java {
background: linear-gradient(135deg, var(--el-color-warning) 0%, var(--el-color-warning-light-3) 100%);
box-shadow: 0 2px 4px rgba(230, 162, 60, 0.3);
}
```
---
## 演练场工作流程
### 执行Python代码的完整流程:
```
用户在演练场提交代码
↓
前端发送 /v2/playground/test POST请求
↓
PlaygroundApi.test() 接收请求
↓
PyPlaygroundExecutor 创建实例
↓
executeParseAsync() 执行流程:
├─ PyCodeSecurityChecker.check() - 安全检查
├─ PyCodePreprocessor.preprocess() - 代码预处理
│ ├─ 检测导入的网络库
│ ├─ 加载 requests_guard.py
│ ├─ 注入补丁到代码头部
│ └─ 返回预处理日志:"✓ 网络请求安全拦截已启用..."
├─ playgroundLogger.infoJava() - 记录预处理日志
├─ 执行预处理后的代码
│ └─ 代码运行时会自动应用猴子补丁
└─ 收集所有日志和执行结果
↓
API返回包含日志的响应
↓
前端接收并在演练场控制台显示所有日志:
├─ [JAVA] 预处理日志(橙色,带[JAVA]标签)
├─ [PYTHON] Python脚本中的 print/logger 日志(蓝色,带[PYTHON]标签)
└─ [Guard] 网络请求拦截日志(由补丁中的GuardLogger生成)
```
---
## 演练场控制台日志示例
```
[10:15:30] INFO [JAVA] ✓ 网络请求安全拦截已启用 (检测到: requests, urllib) | 已动态注入 requests_guard 猴子补丁
[10:15:31] DEBUG [JAVA] [Java] 安全检查通过
[10:15:31] INFO [JAVA] [Java] 开始执行parse方法
[10:15:32] DEBUG [JAVA] [Java] 执行Python代码
[10:15:33] INFO [PYTHON] 正在解析链接: https://example.com/s/abc123
[10:15:33] DEBUG [PYTHON] [Guard] 允许 GET https://example.com/s/abc123
[10:15:34] INFO [PYTHON] 获取到 5 个文件
[10:15:35] INFO [JAVA] [Java] 解析成功,返回结果: https://download.example.com/file.zip
```
---
## 安全特性
### 1. 网络请求拦截范围
- ✅ 拦截本地地址(127.0.0.1, localhost)
- ✅ 拦截私网地址(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 等)
- ✅ 拦截危险端口(SSH, MySQL, Redis等)
- ✅ DNS解析结果验证
- ✅ 协议检查(仅允许http/https)
### 2. 代码执行安全
- ✅ 静态安全检查(在预处理前)
- ✅ 动态补丁注入(不修改用户代码)
- ✅ 审计日志记录(所有网络请求可追踪)
- ✅ 超时控制(30秒执行超时)
### 3. 扩展性
- ✅ 支持添加更多网络库拦截
- ✅ 支持自定义黑名单/白名单
- ✅ 支持热更新补丁代码
- ✅ 支持自定义审计日志处理
---
## 技术栈
### 前端 (Vue.js 3)
- Monaco Editor - 代码编辑
- Element Plus - UI组件
- FileReader API - 文件导入
- Clipboard API - 粘贴操作
### 后端 (Java)
- Vert.x 4.5.23 - 异步框架
- GraalVM Polyglot - Python执行
- SLF4J + Logback - 日志记录
- 正则表达式 - 代码分析
### Python
- 标准库:socket、urllib
- 无额外依赖 - 补丁模块独立运行
---
## 文件清单
### 新增文件
1. `parser/src/main/resources/requests_guard.py` - 猴子补丁模块
2. `parser/src/main/java/cn/qaiu/parser/custompy/PyCodePreprocessor.java` - 代码预处理器
### 修改的文件
1. `web-front/src/views/Playground.vue` - 编辑器UI和日志显示
2. `parser/src/main/java/cn/qaiu/parser/custompy/PyPlaygroundExecutor.java` - 集成预处理器
---
## 使用方式
### 1. 导入文件
点击 "更多操作" → "导入文件" → 选择本地.js/.py/.txt文件
### 2. 粘贴代码
- 使用 "粘贴" 按钮
- 或直接 Ctrl+V/Cmd+V
- 支持多行代码一次性粘贴
### 3. 查看安全拦截日志
执行包含 requests/urllib 的Python代码时:
1. 演练场控制台自动显示"✓ 网络请求安全拦截已启用"
2. 所有网络请求都会记录在日志中
3. 被拦截的请求显示拦截原因
---
## 性能考虑
- **代码预处理** - 仅在需要时执行,时间复杂度 O(n)
- **补丁加载** - 一次性从资源文件加载,缓存在内存
- **日志记录** - 异步操作,不阻塞代码执行
- **前端显示** - 虚拟列表(当日志过多时)
---
## 测试建议
### 功能测试
1. ✅ 导入不同格式的文件
2. ✅ 粘贴多行代码和特殊字符
3. ✅ 执行包含 requests 的Python代码
4. ✅ 验证网络请求拦截日志
5. ✅ 测试移动端编辑体验
### 安全测试
1. ✅ 尝试访问 127.0.0.1 等本地地址
2. ✅ 尝试访问私网地址
3. ✅ 尝试连接危险端口
4. ✅ 验证日志中显示拦截原因
---
## 后续增强建议
1. **集成更多网络库** - httpx, aiohttp, twisted 等
2. **白名单支持** - 允许特定地址/域名访问
3. **审计日志持久化** - 保存到文件/数据库
4. **性能优化** - 缓存IP解析结果
5. **UI优化** - 日志搜索、过滤、导出功能
6. **告警机制** - 频繁访问被拦截地址时告警
---
## 许可证
遵循项目原有许可证
---
## 贡献者
GitHub Copilot
---
*本文档最后更新于 2026年1月18日*