feat: 注入http.get/post到Groovy脚本,PAR也能发起真实HTTP请求
This commit is contained in:
@@ -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); }
|
||||
|
||||
Reference in New Issue
Block a user