# IdeaHttpRequestBatch **Repository Path**: cashbyfb/idea-http-request-batch ## Basic Information - **Project Name**: IdeaHttpRequestBatch - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-15 - **Last Updated**: 2026-10-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # HTTP 批量测试台(HttpRequestBatch) 把 IDEA HTTP Client 的 `.http` / `.rest` 集合变成一个**可视化批量测试工具**:指定目录 → 自动解析出所有接口 → 单个发送或全量/勾选批量执行 → 展示请求参数与响应结果 → 每次执行自动落成历史文件。 前端 Vue 3 直接内嵌在 Spring Boot 的 `static` 目录里,**打成一个 jar 就能跑,不需要 npm / 前端构建**。 ``` http://localhost:8080/ │ ▼ ┌───────────────────────────────────────────────┐ │ Vue3 单页(static/index.html + app.js) │ ├───────────────────────────────────────────────┤ │ /api/scan 目录 → 解析 .http │ │ /api/run 单个 / 少量同步执行 │ │ /api/batch/* 异步批量 + 进度轮询 + 停止 │ │ /api/history/* 历史记录文件管理 │ ├───────────────────────────────────────────────┤ │ HttpFileParser → VariableResolver → Executor │ │ ScriptRunner(Nashorn 断言) → HistoryService │ └───────────────────────────────────────────────┘ │ ▲ ▼ │ 被测接口(demo 用内置 /mock/**) .http 文件 + http-client.env.json ``` --- ## 一、快速开始 ### 1. IDEA(开发调试) 1. 用 IDEA 打开本目录(识别为 Maven 工程,等待依赖下载完成); 2. 运行 `HttpRequestBatchApplication`; 3. 控制台会输出可点击地址(Ctrl + 点击直接打开浏览器): ``` ========================================================== 接口批量测试台已启动,点击(或 Ctrl+点击)下面的地址打开页面: http://localhost:8080/ http://192.168.0.113:8080/ 默认集合目录 : D:\...\HttpRequestBatch\demo-api 历史记录目录 : D:\...\HttpRequestBatch\history(启动参数 http-batch.history-dir 可改) 运行环境 : Windows 10, Java 1.8.0_301 换端口 : --server.port=9090 或环境变量 SERVER_PORT=9090 ========================================================== ``` > 需要 IDEA 开启 Annotation Processing(Settings → Build → Compiler → Annotation Processors,2024.1 默认开启),否则 Lombok 报找不到 getter/setter。 ### 2. 命令行 / Windows / Linux / macOS 两个启动脚本命令完全对齐(Linux/macOS 用 `run.sh`,Windows 用 `run.bat`): ```text run [集合目录] [端口] 前台运行(默认,Ctrl+C 停止) start [集合目录] [端口] 后台运行(写 logs/app.pid) stop 停止后台实例 restart 重启后台实例 status 查看进程与健康状态 log 实时跟踪日志 build 只重新打 jar 包 help 帮助 ``` ```bash # Linux / macOS chmod +x run.sh ./run.sh # 前台,默认集合目录 + 8080 ./run.sh start # 后台 ./run.sh start /data/http-api 9090 ./run.sh restart && ./run.sh log # Windows cmd> run.bat start cmd> run.bat start D:\data\http-api 9090 cmd> run.bat restart cmd> run.bat status ``` 也可以用原生方式启动(脚本内部就是这么做的): ```bash mvn -B package -DskipTests java -jar target/http-request-batch.jar java -Dfile.encoding=UTF-8 -jar target/http-request-batch.jar --server.port=9090 HTTP_BATCH_DIR=/data/api SERVER_PORT=9090 java -jar http-request-batch.jar ``` > 集合目录能否在页面上改,取决于 `http-batch.browse-enabled`(环境变量 `HTTP_BATCH_BROWSE_ENABLED`,仓库里默认 **false**): > > - `false`:页面不显示「浏览…」按钮,「集合目录」变成**只读展示**(回车不再触发扫描),目录由启动参数决定: > `run.sh start /data/http-api`、`HTTP_BATCH_DIR=/data/http-api`、`--http-batch.default-dir=/data/http-api`;改完点「重新扫描」即可。 > - `true`:目录可直接输入(回车 = 规范化后重新扫描,失焦自动去空白/引号),并显示「浏览…」按钮走 `/api/browse` 逐级选目录。 ### 3. 试用(不依赖任何外部服务) 工程自带 `demo-api/` 集合和内置 Mock 接口,启动后直接点「▶ 运行全部」即可看到 24 个接口跑完:22 通过 + 2 个故意做失败的红字用例。 --- ## 二、界面说明 | 区域 | 作用 | | --- |--------------------------------------------------------| | 顶部工具栏 | 集合目录(`browse-enabled=false` 时只读展示,为 `true` 时可输入 + 「浏览…」弹层选目录);重新扫描;环境下拉;变量覆盖;并发(串行~20 线程);共享 Cookie | | 运行按钮 | ▶ 运行全部、▶ 运行选中、▶ 运行筛选结果、■ 停止、历史记录、清空结果 | | 进度条 | 总数 / 已执行 / 通过 / 失败 / 异常 / 耗时 | | 左侧列表 | 按文件分组展示接口,可勾选、单条运行、按名称/URL/方法过滤、文件级小统计 | | 右侧「请求参数」 | 方法、URL 原文与解析后的实际地址、请求头(声明值 + 替换后的值)、请求体、前置/响应脚本、文件原文 | | 右侧「响应结果」 | 状态码、耗时、大小、实际发出的完整报文、响应头、响应体(JSON 可格式化/复制)、当次产生的全局变量 | | 右侧「断言」 | 逐条 PASS/FAIL 与失败原因、`client.log` 输出、脚本错误 | | 右侧「批量汇总」 | 失败优先排序的结果表,点行跳到对应接口 | | 历史记录弹层 | 列表(过滤 / 只看失败 / 删除 / 重跑)+ 详情(展开看报文、导入主界面、按记录重跑、导出 JSON) | --- ## 三、支持的 .http 语法 沿用 IDEA HTTP Client 写法,**同一份文件在 IDEA 里也能正常跑**。 | 语法 | 说明 | | --- | --- | | `### 名称` | 请求分隔符,`###` 后的文字作为接口名(优先级最高) | | `# @name xxx` | 用元数据命名接口 | | `# @no-redirect` | 不跟随 302 重定向 | | `# @timeout 8000` | 本条请求单独设置读取超时(ms) | | `POST {{baseUrl}}/users HTTP/1.1` | 请求行,方法可省略(默认 GET),`HTTP/1.1` 可省略 | | `Header-Name: value` | 请求头,值里可用 `{{变量}}` | | 空行之后的内容 | 请求体(JSON / XML / 文本 / multipart 均可) | | `< {% ... %}` | 前置脚本,可 `request.variables.set('id', 7)` 给本条请求动态造参 | | `> {% ... %}` | 响应脚本 / 断言 | | `< ./data/user.json` | 请求体整体来自文件(按二进制发送,支持中文与文件) | | multipart 内的 `< ./file.txt` | 分片内容内联为文件文本 | | `GRAPHQL {{host}}/graphql` | body 空行后接 `variables` JSON,自动包装成 `{query, variables}` | | `application/x-www-form-urlencoded` | 支持一行一个表单参数,自动转成 `a=1&b=2` 并 URL 编码 | | `# 注释` / `// 注释` | 请求级注释(body 内的 `#` 行仍是正文) | 示例: ```http ### 用户列表 GET {{baseUrl}}/mock/users?page=1&size={{pageSize}} Accept: application/json > {% client.test("HTTP 状态码为 200", function () { client.assert(response.status === 200, "实际状态码: " + response.status); }); client.log("返回用户总数: " + response.body.asJson.total); %} ### 新增用户-请求体来自文件 POST {{baseUrl}}/mock/users Content-Type: application/json X-Token: {{loginToken}} < ./data/new-user.json ``` --- ## 四、变量与多环境 `http-client.env.json`(放在集合目录下,可放在任意子目录): ```json { "$shared": { "tenant": "demo", "apiVersion": "v1" }, "local": { "baseUrl": { "value": "http://localhost:8080", "description": "内置 mock 服务地址" }, "loginToken": "demo-static-token", "pageSize": "10" }, "dev": { "baseUrl": "http://127.0.0.1:8080", "loginToken": "dev-token", "pageSize": "20" } } ``` - 支持 `{ "key": {"value": "...", "description": "..."} }` 对象写法和直接写值; - `private.http-client.env.json` 会覆盖同名变量(放密钥用); - `.env`(`KEY=VALUE`)作为所有环境的兜底变量; - 变量优先级:页面「变量覆盖」 > 所选环境 > `$shared` / `.env`; - 页面「变量覆盖」里的临时变量会被记进历史记录,方便复现; - 扫描时若发现 `{{var}}` 在环境里没定义(且不是脚本 `set` 出来的),顶部会黄条提示。 ### 断言脚本可用的对象 | 对象 | 说明 | | --- | --- | | `response.status` / `response.code` | HTTP 状态码 | | `response.body.text` / `content` / `pretty` | 响应体字符串 | | `response.body.asJson` | JSON 解析结果(非 JSON 为 `null`) | | `response.headers.get('set-cookie')` / `response.headers.all` | 响应头 | | `response.contentType.mimeType` / `full` | 内容类型 | | `request.method` / `url` / `body` / `headers.get()` | 实际发出的请求 | | `request.variables.set(k, v)` | 仅对当前请求生效的变量(前置脚本用) | | `client.global.set(k, v)` / `get(k)` | 全局变量,**同一次批量执行内**后续请求可用 `{{k}}` | | `client.test('名称', function(){...})` | 定义一个断言用例 | | `client.assert(表达式, '失败信息')` | 断言,失败则用例标红 | | `client.log(...)` | 输出到「断言」页的脚本日志 | | `environment` / `client.environment` | 当前环境变量与名称 | > 状态判定规则:写了断言就**以断言结果为准**(允许“预期 401/404”这类反向用例通过);没写断言时 HTTP ≥ 400 判为失败。 --- ## 五、批量执行 - **范围**:全部 / 勾选 / 当前筛选结果 / 单文件 / 单接口; - **并发**:串行或 2~20 线程(异步任务 + 500ms 轮询进度,边跑边出结果); - **停止**:跑到哪停到哪,已完成的结果保留,并且**也会写入历史记录**; - **共享 Cookie**:勾选后一次批量共用一个 CookieStore,支持“登录 → 后续带 Cookie 访问”; - **顺序依赖**:`client.global.set('token', ...)` 依赖执行顺序,**有前后依赖的集合请串行**(并发下登录接口可能还没跑完)。 --- ## 六、历史记录 每次执行落一个文件,便于归档、对比、追溯: ``` history/ ├─ H20260915-225702-c96a.json ← 一次执行 = 一个 pretty JSON 文件 └─ index.json ← 列表索引(删除后可从记录文件自动重建) ``` 记录字段:`id / type(SINGLE|BATCH) / time / elapsedMs / dir / envName / parallel / keepSession / variables / requestIds / collectionName / total / success / failed / errors / assertions / assertionsFailed / results[]`,`results[]` 内含实际请求(URL、头、体)、响应(状态、头、体、大小)、断言明细、脚本日志、警告、当次产生的全局变量。 页面上支持:关键字过滤、只看有失败的、查看详情、展开单条看报文、**导入到主界面**、**按这条记录重跑**(自动恢复目录/环境/并发/Cookie/临时变量)、删除、清空、导出 JSON。 配置: ```yaml http-batch: history-dir: ${HTTP_BATCH_HISTORY_DIR:./history} # 相对路径优先工作目录,不可写时回退 jar 同级 history-max-records: 200 # 超出自动删除最早的记录文件 history-max-body: 32768 # 单个响应体保留字符数,防止文件膨胀 ``` --- ## 七、REST 接口 统一响应包装 `{"ok": true|false, "data": ..., "message": ...}`。 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/api/meta` | 工作目录、默认集合目录、历史记录目录、OS/Java/编码等 | | POST | `/api/scan` | `{"dir":"D:/x/http","force":true}` → 文件、接口、环境、告警 | | POST | `/api/run` | 同步执行,`{"dir","envName","requestIds":[],"variables":{}}` → 结果数组 | | POST | `/api/batch/start` | 异步批量,额外支持 `parallel`、`keepSession`;返回 `taskId`、`total` | | GET | `/api/batch/progress?taskId=` | 进度 + 已完成结果列表 | | POST | `/api/batch/stop?taskId=` | 请求停止 | | GET | `/api/browse?path=` | 目录浏览(只列子目录与 .http/.rest);`browse-enabled=false` 时返回 `ok:false`,前端也不再渲染入口 | | GET | `/api/history/list?keyword=&onlyFailed=&limit=` | 历史记录列表 | | GET | `/api/history/detail?id=` | 单条记录完整内容 | | POST | `/api/history/delete?id=` / `/api/history/clear` | 删除一条 / 清空 | | GET | `/` | Vue 页面(jar 内置) | 示例: ```bash curl -X POST http://localhost:8080/api/scan -H 'Content-Type: application/json' \ -d '{"dir":"D:/develop/demo-api","force":true}' curl -X POST http://localhost:8080/api/batch/start -H 'Content-Type: application/json' \ -d '{"dir":"D:/develop/demo-api","envName":"local","parallel":5,"keepSession":true,"requestIds":[]}' ``` ### 内置演示接口 `/mock/**` 为了让 demo 集合开箱即用,工程自带一组 Mock 接口(**无鉴权,正式使用时请自行关闭**): `GET /mock/health`、`GET /mock/users?name=&page=&size=`、`GET /mock/users/{id}`(不存在返回 404)、 `POST /mock/users`(缺 `X-Token` 返回 401,成功 201)、`PUT /mock/users/{id}`、`DELETE /mock/users/{id}`、 `POST /mock/login`(返回 token 并种 Cookie)、`GET /mock/profile`(需 token)、`/mock/echo`(回显方法/参数/头/体)、 `GET /mock/text`、`GET /mock/xml`、`GET /mock/status/{code}`、`GET /mock/delay?ms=`、`GET /mock/random`。 --- ## 八、全部配置项 | 配置 | 环境变量 | 默认值 | 说明 | | --- | --- | --- | --- | | `server.port` | `SERVER_PORT` | 8080 | 端口 | | `http-batch.default-dir` | `HTTP_BATCH_DIR` | `./demo-api` | 集合目录(`browse-enabled=false` 时页面上只读展示,靠启动参数/环境变量决定) | | `http-batch.scan-depth` | | 6 | 递归扫描深度 | | `http-batch.max-files` | | 500 | 单次最多解析文件数 | | `http-batch.connect-timeout` | | 10000 | 连接超时 ms | | `http-batch.read-timeout` | | 60000 | 读取超时 ms | | `http-batch.max-response-size` | | 2097152 | 响应体留存上限,超出截断 | | `http-batch.history-dir` | `HTTP_BATCH_HISTORY_DIR` | `./history` | 历史记录目录 | | `http-batch.history-max-records` | | 200 | 保留记录条数 | | `http-batch.history-max-body` | | 32768 | 记录中响应体保留字符数 | | `http-batch.mock-enabled` | `HTTP_BATCH_MOCK_ENABLED` | true | 内置 `/mock/**` 演示接口开关,生产建议 false | | `http-batch.browse-enabled` | `HTTP_BATCH_BROWSE_ENABLED` | true(application.yml 里已改成 false) | 是否允许服务端浏览任意目录;关闭后前端隐藏「浏览…」按钮与弹层,集合目录变只读,`/api/browse` 直接返回 `ok:false` | | `logging.file.name` | `HTTP_BATCH_LOG_FILE` | `logs/http-request-batch.log` | 日志文件(同时保留控制台输出) | 其他常用 JVM/进程参数:`JAVA_HOME`、`JAVA_OPTS`(默认 `-Xms128m -Xmx512m -Dfile.encoding=UTF-8`)、 `USER_TIMEZONE`(run.sh 里的时区,默认 `Asia/Shanghai`)、`HTTP_BATCH_EXTRA_ARGS`(追加任意 `--key=value`)。 --- ## 九、生产部署 ### 9.1 部署包与目录规划 只需要一个 jar + 你的接口集合,其余目录首次运行时自动创建: ``` /opt/http-batch/ ├─ http-request-batch.jar # mvn package 产物(内含前端页面) ├─ run.sh # Linux/macOS 启动脚本 ├─ api/ # 你的 .http / .rest 集合 + http-client.env.json ├─ history/ # 自动创建:历史记录 JSON └─ logs/ # 自动创建:应用日志 + app.pid ``` 相对路径的解析规则(`default-dir` / `history-dir` 都适用): 1. 绝对路径直接用; 2. 相对路径基于**进程工作目录**(`user.dir`); 3. 工作目录不可写时(典型如 systemd 里 `WorkingDirectory=/`)回退到 **jar 同级目录**。 集合目录本身也有回退:配置目录 → jar 同级同名目录 → jar 旁边的 `demo-api` → jar 目录(里面有 .http 时)。启动横幅会打印最终解析结果,部署时看一眼即可确认。 ### 9.2 JDK 选择 | JDK | 结果 | | --- | --- | | **JDK 8 / 11(推荐)** | 全部功能可用(含 `{% %}` 断言脚本,依赖 JDK 自带的 Nashorn) | | JDK 15+(17/21) | 能启动、能发请求、能按状态码判成败;但断言脚本被跳过,启动横幅与结果里会提示 ⚠ | 建议用 Temurin 8/11,并在脚本前指定:`JAVA_HOME=/usr/lib/jvm/temurin-11 ./run.sh start`(或直接 `JAVA_BIN=/path/to/java`)。 ### 9.3 Linux:systemd 托管(推荐) ```bash # /etc/http-batch/env HTTP_BATCH_DIR=/opt/http-batch/api HTTP_BATCH_HISTORY_DIR=/var/lib/http-batch/history HTTP_BATCH_LOG_FILE=/var/log/http-batch/http-request-batch.log SERVER_PORT=9090 HTTP_BATCH_MOCK_ENABLED=false JAVA_HOME=/usr/lib/jvm/temurin-11 ``` ```ini # /etc/systemd/system/http-batch.service [Unit] Description=HTTP Request Batch After=network.target [Service] Type=simple User=httpbatch WorkingDirectory=/opt/http-batch EnvironmentFile=/etc/http-batch/env # run 是前台模式,交给 systemd 监督进程 ExecStart=/opt/http-batch/run.sh run Restart=on-failure RestartSec=5 # java 收到 SIGTERM 退出常返回 143,不算异常 SuccessExitStatus=143 15 NoNewPrivileges=true PrivateTmp=true ReadWritePaths=/var/lib/http-batch /var/log/http-batch /opt/http-batch/api [Install] WantedBy=multi-user.target ``` ```bash systemctl daemon-reload && systemctl enable --now http-batch systemctl status http-batch && journalctl -u http-batch -f curl -s localhost:9090/api/meta | head -c 200 ``` 不想用 systemd 时,`./run.sh start|stop|restart|status|log` 已够用(nohup + pid 文件,启动后会轮询端口确认已监听,失败则自动打印日志尾部)。 ### 9.4 Windows:后台运行与开机自启 ```cmd cmd> run.bat start D:\api 9090 :: 后台无窗口启动(javaw),pid 写入 logs\app.pid cmd> run.bat status :: 打印 pid + 调 /api/meta 自检 cmd> run.bat restart :: 先 stop 再 start cmd> run.bat stop :: 先优雅 kill,3 秒未退再 /F 强制 cmd> run.bat log :: 跟踪 logs\http-request-batch.log ``` 实现细节:`Start-Process -WindowStyle Hidden` 启动,**真正的进程号是按监听端口反查得到的**(兼容 Oracle 的 `javapath\javaw.exe` 这类 launcher stub);启动后最多等 25 秒确认端口已监听,否则打印日志尾部并以非 0 退出。 > `run.bat` 全文件保持纯 ASCII:一旦 `chcp 65001` + 中文,cmd 会因字节偏移错解析注释行(实测会把注释当命令执行)。 开机自启(二选一): ```cmd :: 方案 A:任务计划程(登录/开机自动后台拉起) schtasks /Create /TN HttpBatch /SC ONSTART /TR "D:\http-batch\run.bat start" /RU SYSTEM /F :: 方案 B:注册成 Windows 服务(推荐用 WinSW / NSSM 包装) :: WinSW:把 WinSW.NET4.exe + 下面这个 xml 放同一目录,执行 WinSW install :: http-batchHTTP Request Batch :: java-Dfile.encoding=UTF-8 -jar target\http-request-batch.jar --server.port=9090 :: roll-by-size ``` ### 9.5 反向代理与访问控制 工具本身**没有登录体系**,一旦开到网外必须自己加访问控制: ```nginx server { listen 80; server-name http-batch.internal; location / { auth_basic "HTTP Batch"; # 至少加一层 Basic Auth auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://127.0.0.1:9090; proxy_set_header Host $host; proxy_read_timeout 300s; # 批量跑耗时长的接口用 } location /mock/ { return 404; } # 反代层再兼一道演示接口 } ``` 只本机使用时,建议直接限定监听地址:`--server.address=127.0.0.1`(可作为 `HTTP_BATCH_EXTRA_ARGS` 传入)。 ### 9.6 日志、历史与磁盘占用 | 项 | 默认行为 | 调整方式 | | --- | --- | --- | | 应用日志 | `logs/http-request-batch.log`,按天+按大小滚动,单件 20MB、保留 14 天、总量 500MB | `HTTP_BATCH_LOG_FILE` / `logging.logback.rollingpolicy.*` | | 历史记录 | 最名 200 条,超出自动删最早的 JSON | `http-batch.history-max-records` | | 响应体体积 | 记录里每个响应体最多 32K 字符 | `http-batch.history-max-body`(敏感环境建议调小) | | 后台启动输出 | `logs/stdout.log`(run.sh);run.bat 那么无窗口,看日志文件即可 | — | 安全须知:历史记录含**完整响应体**(可能带 token、用户数据),history 目录请限权限(Linux `chmod 700`),或关小 `history-max-body`;备份就是拷走整个目录(JSON 可直接 diff)。 ### 9.7 升级、回滚与多实例 ```bash # 升级:换 jar → restart(秒级,集合和历史不动) cp http-request-batch.jar.new /opt/http-batch/http-request-batch.jar && ./run.sh restart # 回滚:换回旧 jar 再 restart 即可 # 多实例(不同端口 + 各自历史目录,互不干扰) ./run.sh start /api/project-a 9091 HTTP_BATCH_HISTORY_DIR=/data/hist-a ./run.sh start /api/project-a 9091 ``` 健康检查用 `GET /api/meta`(无依赖、返回快);它也能确认集合目录、历史目录、JDK、mock 开关等运行参数。应用本身无状态(只读扫描集合、只写 history/logs),随时可停可换机器。 ### 9.8 常见部署问题 | 现象 | 原因 / 处理 | | --- | --- | | `run.bat start` 直接提示 `port 8080 is already used by pid=xxx` | 端口被占,换端口或先 `run.bat stop` | | 启动报“端口 25s 未监听”并刷日志 | 看日志尾部,通常是集合目录不存在或端口冲突 | | 断言没执行、`assertions=0` | JDK 15+ 无 Nashorn,换 JDK 8/11 | | 列表为空 / 接口 0 个 | 启动横幅里的「默认集合目录」方不对,用 `HTTP_BATCH_DIR` 指定 | | Windows 控制台中文乱码 | 不影响功能;日志文件是 UTF-8,用编辑器打开即可 | | Linux 上响应中文乱码 | 加 `-Dfile.encoding=UTF-8`(脚本已默认带上) | | 页面看不到环境/变量 | `http-client.env.json` 要放在集合目录或其子目录下 | ### 9.9 可选:做成平台原生安装包 当前交付形式是 **jar + 启动脚本**(跨平台、体积小、带 JDK 即可跑)。如果确实须“目标机器不装 Java”的安装包,可按下面两条路线扩展(本仓库未内置对应构建配置): ```bash # 路线 A:jpackage(JDK 17+ 执行)自带精简运行时,产物 .msi/.deb/.rpm/.dmg jlink --add-modules ALL-MODULE-PATH --strip-debug --output runtime jpackage --type app-image --name http-request-batch \ --runtime-image runtime --input target --jar http-request-batch.jar \ --java-options "-Dfile.encoding=UTF-8" ``` 注意:jpackage 需要 JDK 17+ 来打包,而 17+ 没有 Nashorn,因此走这条路线时要额外引入 Rhino (`org.mozilla:rhino` + `rhino-engine`)作为 `{% %}` 脚本的兼底引擎;且 x86 / arm64 必须在对应架构上构建(x86 机器交叉不了 arm64,可用 Docker + QEMU 或 CI 矩阵)。 路线 B(GraalVM native-image 真二进制)需先升级到 Spring Boot 3 + Java 17,并把 Nashorn 换成 GraalJS,改造量最大,按本项目体量性价比不高。 --- ## 十、目录结构 ``` ├─ pom.xml ├─ run.sh / run.bat # 启动脚本(start/stop/restart/status/log),Linux 与 Windows 命令一致 ├─ .gitattributes # 强制 *.sh 用 LF、*.bat 用 CRLF ├─ demo-api/ # 示例集合(可直接在 IDEA 里跑) │ ├─ http-client.env.json │ ├─ 01-用户管理.http 02-登录会话.http 03-工具与异常.http │ ├─ sub/04-更多.rest │ └─ data/new-user.json ├─ history/ # 运行后生成的历史记录(已 gitignore) ├─ logs/ # 运行后生成的日志与 app.pid(已 gitignore) └─ src/main/java/org/example/httpbatch/ ├─ HttpRequestBatchApplication.java # 启动 + 打印可点击访问地址 ├─ config/HttpBatchProperties.java ├─ model/ # RequestDef FileInfo ScanResult EnvInfo TestResult ... ├─ service/ │ ├─ HttpFileParser.java # .http 语法解析 │ ├─ Scanner.java # 目录扫描 + 默认目录回退 │ ├─ EnvService.java # 环境文件加载 │ ├─ VariableResolver.java # {{var}} 替换 │ ├─ RequestExecutor.java # 发请求(Apache HttpClient) │ ├─ ScriptRunner.java # Nashorn 跑断言脚本 │ └─ BatchService.java HistoryService.java └─ controller/ ├─ TestController.java # /api/** └─ MockApiController.java # /mock/** 演示接口 ``` --- ## 十一、开发说明 ```bash mvn -B -q compile # 编译 mvn -B -q package -DskipTests # 打可执行 jar(target/http-request-batch.jar) bash -n run.sh # 启动脚本语法自检 ``` - 单元测试:`HttpFileParserTest`(解析语法)、`HistoryServiceTest`(记录存储/索引/裁剪)。请在 **IDEA 里运行**;命令行 `mvn test` 依赖 `surefire-junit-platform`,若私服不可用会失败。 - 前端不经过构建:直接改 `src/main/resources/static/{index.html,app.js,style.css}`,刷新页面即可(IDEA 里改完需重新编译资源或重启)。Vue 3 走 CDN(unpkg,失败自动切 jsdelivr);离线环境把 `vue.global.prod.js` 放到 `static/vendor/` 并改 `index.html` 里的引用。 - 行尾约定:`.gitattributes` 已固定 `*.sh` 为 LF、`*.bat` 为 CRLF,改完脚本后用 `unix2dos run.bat` / `dos2unix run.sh` 归一化即可。 --- ## 十二、已知限制 1. **JS 脚本依赖 JDK 自带的 Nashorn**:JDK 15+(如 17/21)已移除,此时 `{% %}` 断言会被跳过(启动日志与结果里都会提示),应用本身仍能正常发请求、按状态码判定。需要高版本 JDK 跑断言可自行引入 Rhino,或固定使用 JDK 8 / 11。 2. 并发执行时用例之间不保证顺序,带依赖(登录取 token)的集合请用串行。 3. Cookie / `client.global` 变量只在**一次执行内**共享,不做跨执行持久化。 4. `GET/HEAD/OPTIONS/TRACE/DELETE` 不发送请求体(结果里会给出提示)。 5. multipart 分片内的 `< file` 按文本内联,二进制文件请整段 `< ./file` 引用。 6. `> {% ... %}` 之外的响应导出语法(如 `<> response.json`)只记录元数据,不写文件。 7. 本工具定位是本地/内网开发自测,**自身没有登录鉴权**:对外部署请放到内网或加反代鉴权,并用 `HTTP_BATCH_MOCK_ENABLED=false` 关掉演示接口、`HTTP_BATCH_BROWSE_ENABLED=false` 关掉任意目录浏览;历史记录含完整响应体,注意落盘目录权限。