diff --git a/parser/doc/TYPESCRIPT_ES5_IMPLEMENTATION.md b/parser/doc/TYPESCRIPT_ES5_IMPLEMENTATION.md new file mode 100644 index 0000000..ea2a1b3 --- /dev/null +++ b/parser/doc/TYPESCRIPT_ES5_IMPLEMENTATION.md @@ -0,0 +1,378 @@ +# TypeScript/ES6+ 浏览器编译与Fetch API实现 + +## 项目概述 + +本实现提供了**纯前端TypeScript编译 + 后端ES5引擎 + Fetch API适配**的完整解决方案,允许用户在浏览器中编写TypeScript/ES6+代码(包括async/await),编译为ES5后在后端Nashorn JavaScript引擎中执行。 + +## 架构图 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 浏览器端 (计划中) │ +├─────────────────────────────────────────────────────────┤ +│ 用户编写 TypeScript/ES6+ 代码 (async/await) │ +│ ↓ │ +│ TypeScript.js 浏览器内编译为 ES5 │ +│ ↓ │ +│ 生成的 ES5 代码发送到后端 │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ 后端 (已实现) │ +├─────────────────────────────────────────────────────────┤ +│ 1. 接收 ES5 代码 │ +│ 2. 注入 fetch-runtime.js (Promise + fetch polyfill) │ +│ 3. 注入 JavaFetch 桥接对象 │ +│ 4. Nashorn 引擎执行 ES5 代码 │ +│ 5. fetch() → JavaFetch → JsHttpClient → Vert.x │ +└─────────────────────────────────────────────────────────┘ +``` + +## 已实现功能 + +### ✅ 后端 ES5 执行环境 + +#### 1. Promise Polyfill (完整的 Promise/A+ 实现) + +文件: `parser/src/main/resources/fetch-runtime.js` + +**功能特性:** +- ✅ `new Promise(executor)` 构造函数 +- ✅ `promise.then(onFulfilled, onRejected)` 链式调用 +- ✅ `promise.catch(onRejected)` 错误处理 +- ✅ `promise.finally(onFinally)` 清理操作 +- ✅ `Promise.resolve(value)` 静态方法 +- ✅ `Promise.reject(reason)` 静态方法 +- ✅ `Promise.all(promises)` 并行等待 +- ✅ `Promise.race(promises)` 竞速等待 + +**实现细节:** +- 纯 ES5 语法,无ES6+特性依赖 +- 使用 `setTimeout(fn, 0)` 实现异步执行 +- 支持 Promise 链式调用和错误传播 +- 自动处理 Promise 嵌套和展开 + +#### 2. Fetch API Polyfill (标准 fetch 接口) + +文件: `parser/src/main/resources/fetch-runtime.js` + +**支持的 HTTP 方法:** +- ✅ GET +- ✅ POST +- ✅ PUT +- ✅ DELETE +- ✅ PATCH +- ✅ HEAD + +**Request 选项支持:** +```javascript +fetch(url, { + method: 'POST', // HTTP 方法 + headers: { // 请求头 + 'Content-Type': 'application/json', + 'Authorization': 'Bearer token' + }, + body: JSON.stringify({ // 请求体 + key: 'value' + }) +}) +``` + +**Response 对象方法:** +- ✅ `response.text()` - 获取文本响应 (返回 Promise) +- ✅ `response.json()` - 解析 JSON 响应 (返回 Promise) +- ✅ `response.arrayBuffer()` - 获取字节数组 +- ✅ `response.status` - HTTP 状态码 +- ✅ `response.ok` - 请求是否成功 (2xx) +- ✅ `response.statusText` - 状态文本 +- ✅ `response.headers.get(name)` - 获取响应头 + +#### 3. Java 桥接层 + +文件: `parser/src/main/java/cn/qaiu/parser/customjs/JsFetchBridge.java` + +**核心功能:** +- 接收 JavaScript fetch API 调用 +- 转换为 JsHttpClient 调用 +- 处理请求头、请求体、HTTP 方法 +- 返回 JsHttpResponse 对象 +- 自动继承现有的 SSRF 防护机制 + +**代码示例:** +```java +public class JsFetchBridge { + private final JsHttpClient httpClient; + + public JsHttpResponse fetch(String url, Map options) { + // 解析 method、headers、body + // 调用 httpClient.get/post/put/delete/patch + // 返回 JsHttpResponse + } +} +``` + +#### 4. 自动注入机制 + +文件: +- `parser/src/main/java/cn/qaiu/parser/customjs/JsParserExecutor.java` +- `parser/src/main/java/cn/qaiu/parser/customjs/JsPlaygroundExecutor.java` + +**注入流程:** +1. 创建 JavaScript 引擎 +2. 注入 JavaFetch 桥接对象 +3. 加载 fetch-runtime.js +4. 执行用户 JavaScript 代码 + +**代码示例:** +```java +// 注入 JavaFetch +engine.put("JavaFetch", new JsFetchBridge(httpClient)); + +// 加载 fetch runtime +String fetchRuntime = loadFetchRuntime(); +engine.eval(fetchRuntime); + +// 现在 JavaScript 环境中可以使用 Promise 和 fetch +``` + +## 使用示例 + +### ES5 风格 (当前可用) + +```javascript +function parse(shareLinkInfo, http, logger) { + logger.info("开始解析"); + + // 使用 fetch API + fetch("https://api.example.com/data") + .then(function(response) { + logger.info("状态码: " + response.status); + return response.json(); + }) + .then(function(data) { + logger.info("数据: " + JSON.stringify(data)); + return data.downloadUrl; + }) + .catch(function(error) { + logger.error("错误: " + error.message); + throw error; + }); + + // 或者继续使用传统的 http 对象 + var response = http.get("https://api.example.com/data"); + return response.body(); +} +``` + +### TypeScript/ES6+ 风格 (需前端编译) + +用户在浏览器中编写: + +```typescript +async function parse( + shareLinkInfo: ShareLinkInfo, + http: JsHttpClient, + logger: JsLogger +): Promise { + try { + logger.info("开始解析"); + + // 使用标准 fetch API + const response = await fetch("https://api.example.com/data"); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + logger.info(`下载链接: ${data.downloadUrl}`); + + return data.downloadUrl; + + } catch (error) { + logger.error(`解析失败: ${error.message}`); + throw error; + } +} +``` + +浏览器编译为 ES5 后: + +```javascript +function parse(shareLinkInfo, http, logger) { + return __awaiter(this, void 0, void 0, function() { + var response, data, error_1; + return __generator(this, function(_a) { + switch(_a.label) { + case 0: + _a.trys.push([0, 3, , 4]); + logger.info("开始解析"); + return [4, fetch("https://api.example.com/data")]; + case 1: + response = _a.sent(); + if (!response.ok) { + throw new Error("HTTP " + response.status + ": " + response.statusText); + } + return [4, response.json()]; + case 2: + data = _a.sent(); + logger.info("下载链接: " + data.downloadUrl); + return [2, data.downloadUrl]; + case 3: + error_1 = _a.sent(); + logger.error("解析失败: " + error_1.message); + throw error_1; + case 4: return [2]; + } + }); + }); +} +``` + +## 文件结构 + +``` +parser/ +├── src/main/ +│ ├── java/cn/qaiu/parser/customjs/ +│ │ ├── JsFetchBridge.java # Java 桥接层 +│ │ ├── JsParserExecutor.java # 解析器执行器 (已更新) +│ │ └── JsPlaygroundExecutor.java # 演练场执行器 (已更新) +│ └── resources/ +│ ├── fetch-runtime.js # Promise + fetch polyfill +│ └── custom-parsers/ +│ └── fetch-demo.js # Fetch 示例解析器 +├── src/test/java/cn/qaiu/parser/customjs/ +│ └── JsFetchBridgeTest.java # 单元测试 +└── doc/ + └── TYPESCRIPT_FETCH_GUIDE.md # 详细使用指南 +``` + +## 测试验证 + +### 运行测试 + +```bash +# 编译项目 +mvn clean compile -pl parser + +# 运行所有测试 +mvn test -pl parser + +# 运行 fetch 测试 +mvn test -pl parser -Dtest=JsFetchBridgeTest +``` + +### 测试内容 + +文件: `parser/src/test/java/cn/qaiu/parser/customjs/JsFetchBridgeTest.java` + +1. **testFetchPolyfillLoaded** - 验证 Promise 和 fetch 是否正确注入 +2. **testPromiseBasicUsage** - 验证 Promise 基本功能 +3. **示例解析器** - `fetch-demo.js` 展示完整用法 + +## 兼容性说明 + +### 支持的特性 + +- ✅ Promise/A+ 完整实现 +- ✅ Fetch API 标准接口 +- ✅ async/await (通过 TypeScript 编译) +- ✅ 所有 HTTP 方法 +- ✅ Request headers 和 body +- ✅ Response 解析 (text, json, arrayBuffer) +- ✅ 错误处理和 Promise 链 +- ✅ 与现有 http 对象共存 + +### 不支持的特性 + +- ❌ Blob 对象 (使用 arrayBuffer 替代) +- ❌ FormData 对象 (使用简单对象替代) +- ❌ Request/Response 构造函数 +- ❌ Streams API +- ❌ Service Worker 相关 API +- ❌ AbortController (取消请求) + +## 安全性 + +### SSRF 防护 + +继承自 `JsHttpClient` 的 SSRF 防护: +- ✅ 拦截内网 IP (127.0.0.1, 10.x.x.x, 192.168.x.x 等) +- ✅ 拦截云服务元数据 API (169.254.169.254 等) +- ✅ DNS 解析检查 +- ✅ 危险域名黑名单 + +### 沙箱隔离 + +- ✅ SecurityClassFilter 限制类访问 +- ✅ 禁用 Java 对象直接访问 +- ✅ 限制文件系统操作 + +## 性能优化 + +1. **Fetch runtime 缓存** + - 首次加载后缓存在静态变量 + - 避免重复读取文件 + +2. **Promise 异步执行** + - 使用 setTimeout(0) 实现非阻塞 + - 避免阻塞 JavaScript 主线程 + +3. **工作线程池** + - JsParserExecutor: Vert.x 工作线程池 + - JsPlaygroundExecutor: 独立线程池 + - 避免阻塞 Event Loop + +## 前端 TypeScript 编译 (计划中) + +### 待实现步骤 + +1. **添加 TypeScript 编译器** + ```bash + cd web-front + npm install typescript + ``` + +2. **创建编译工具** + ```javascript + // web-front/src/utils/tsCompiler.js + import * as ts from 'typescript'; + + export function compileToES5(sourceCode) { + return ts.transpileModule(sourceCode, { + compilerOptions: { + target: ts.ScriptTarget.ES5, + module: ts.ModuleKind.None, + lib: ['es5', 'dom'] + } + }); + } + ``` + +3. **更新 Playground UI** + - 添加语言选择器 (JavaScript / TypeScript) + - 编译前先检查语法错误 + - 显示编译后的 ES5 代码 (可选) + +## 相关文档 + +- [详细使用指南](parser/doc/TYPESCRIPT_FETCH_GUIDE.md) +- [JavaScript 解析器开发指南](parser/doc/JAVASCRIPT_PARSER_GUIDE.md) +- [自定义解析器扩展指南](parser/doc/CUSTOM_PARSER_GUIDE.md) + +## 总结 + +本实现成功提供了: + +1. **无需 Node 环境** - 纯浏览器编译 + Java 后端执行 +2. **标准 API** - 使用标准 fetch 和 Promise API +3. **向后兼容** - 现有 http 对象仍然可用 +4. **安全可靠** - SSRF 防护和沙箱隔离 +5. **易于使用** - 简单的 API,无学习成本 + +用户可以用现代 JavaScript/TypeScript 编写代码,自动编译为 ES5 后在后端安全执行,同时享受 fetch API 的便利性。 + +## 许可证 + +本项目遵循主项目的许可证。