feat: 注入http.get/post到Groovy脚本,PAR也能发起真实HTTP请求

This commit is contained in:
mediabot-pt
2026-07-01 22:54:45 +08:00
parent 2b474b5cc0
commit c9a78568b0

View File

@@ -22,6 +22,10 @@ import java.util.concurrent.ConcurrentHashMap;
public class GroovyScriptEngine {
private static final ObjectMapper objectMapper = new ObjectMapper();
private static final java.net.http.HttpClient httpClient = java.net.http.HttpClient.newBuilder()
.connectTimeout(java.time.Duration.ofSeconds(10))
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
.build();
private static final GroovyClassLoader classLoader = new GroovyClassLoader(
Thread.currentThread().getContextClassLoader());
/** 类型 → 默认脚本 */
@@ -62,6 +66,14 @@ public class GroovyScriptEngine {
@SuppressWarnings("unchecked")
public Map<String, Object> execute(String groovyScript, String content, String url) {
return execute(groovyScript, content, url, null);
}
/**
* 执行带认证上下文的脚本(用于 PAR 端发起真实 HTTP 请求测试)
*/
@SuppressWarnings("unchecked")
public Map<String, Object> execute(String groovyScript, String content, String url, Map<String, String> siteCtx) {
Map<String, Object> result = new LinkedHashMap<>();
result.put("engine", "groovy");
try {
@@ -71,6 +83,8 @@ public class GroovyScriptEngine {
binding.setVariable("jsoup", new JsoupHelper());
binding.setVariable("json", objectMapper);
binding.setVariable("utils", new ScriptUtils());
binding.setVariable("http", new HttpHelper(httpClient));
if (siteCtx != null) binding.setVariable("_ctx", siteCtx);
GroovyShell shell = new GroovyShell(classLoader, binding);
String fullScript = SCRIPT_PREFIX + groovyScript + "\n// PAR 调用入口\nreturn parse(content, url)";
@@ -175,6 +189,48 @@ public class GroovyScriptEngine {
public Object parse(String html, String baseUri) { return Jsoup.parse(html, baseUri); }
}
/**
* HTTP 请求工具(注入为 http),对齐 mediabo 的 httpGet/httpPost。
* 提供 http.get(url, cookie) 和 http.post(url, body, cookie) 两个方法。
*/
public static class HttpHelper {
private final java.net.http.HttpClient client;
public HttpHelper(java.net.http.HttpClient client) { this.client = client; }
/** HTTP GET,返回响应体字符串 */
public String get(String url, String cookie) {
try {
var builder = java.net.http.HttpRequest.newBuilder()
.uri(java.net.URI.create(url))
.timeout(java.time.Duration.ofSeconds(15))
.header("User-Agent", "PAR/1.0")
.GET();
if (cookie != null && !cookie.isBlank()) builder.header("Cookie", cookie);
var resp = client.send(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofString());
return resp.body();
} catch (Exception e) { throw new RuntimeException("HTTP GET failed: " + url, e); }
}
/** HTTP POST JSON,返回响应体字符串 */
public String post(String url, String body, String auth) {
try {
var builder = java.net.http.HttpRequest.newBuilder()
.uri(java.net.URI.create(url))
.timeout(java.time.Duration.ofSeconds(15))
.header("User-Agent", "PAR/1.0")
.header("Content-Type", "application/json");
if (auth != null && !auth.isBlank()) {
if (auth.startsWith("Bearer") || auth.startsWith("x-api-key"))
builder.header("Authorization", auth);
else builder.header("Cookie", auth);
}
builder.POST(java.net.http.HttpRequest.BodyPublishers.ofString(body != null ? body : ""));
var resp = client.send(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofString());
return resp.body();
} catch (Exception e) { throw new RuntimeException("HTTP POST failed: " + url, e); }
}
}
public static class ScriptUtils {
public String text(Object node) {
try { return (String) node.getClass().getMethod("text").invoke(node); }