From 586a31fdb592f4ab78357e1b79f6462814052d04 Mon Sep 17 00:00:00 2001 From: xuxueli <931591021@qq.com> Date: Sun, 26 Oct 2025 05:47:55 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=9A=E7=94=A8HTTP=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=EF=BC=88httpJobHandler=EF=BC=89=E5=BC=BA=E5=8C=96=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9B=B4=E4=B8=B0=E5=AF=8C=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=AE=BE=E7=BD=AE=EF=BC=8C=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E7=A4=BA=E4=BE=8B=E5=A6=82=E4=B8=8B=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/XXL-JOB官方文档.md | 52 +++- .../job/executor/jobhandler/SampleXxlJob.java | 254 ++++++++++++------ 2 files changed, 212 insertions(+), 94 deletions(-) diff --git a/doc/XXL-JOB官方文档.md b/doc/XXL-JOB官方文档.md index c7bb9828..520b9b13 100644 --- a/doc/XXL-JOB官方文档.md +++ b/doc/XXL-JOB官方文档.md @@ -1186,13 +1186,33 @@ public void demoJobHandler() throws Exception { **执行器内置任务列表:** - a、demoJobHandler:简单示例任务,任务内部模拟耗时任务逻辑,用户可在线体验Rolling Log等功能; - b、shardingJobHandler:分片示例任务,任务内部模拟处理分片参数,可参考熟悉分片任务; -- c、httpJobHandler:通用HTTP任务Handler;业务方只需要提供HTTP链接等信息即可,不限制语言、平台。示例任务入参如下: +- c、httpJobHandler:通用HTTP任务Handler;业务方只需要提供HTTP链接等信息即可,不限制语言、平台。任务入参示例如下: ``` +// 1、简单示例: { "url": "http://www.baidu.com", - "method": "get", + "method": "GET", "data": "hello world" } + +// 2、完整参数示例: +{ + "url": "http://www.baidu.com", // 请求URL + "method": "POST", // 请求方法,支持:GET、POST、HEAD、OPTIONS、PUT、DELETE、TRACE + "contentType": "application/json", // 请求内容类型,支持:application/json、application/x-www-form-urlencoded、application/xml、text/html、text/xml、text/plain + "headers": { // 请求Header,key-value结构 + "header01": "value01" + }, + "cookies": { // 请求Cookie,key-value结构 + "cookie01": "value01" + }, + "timeout": 3000, // 请求超时时间,单位:毫秒 + "data": "request body data", // 请求Body数据,仅针对 POST 请求有效 + "form": { // 请求Form数据,仅针对 GET 请求有效 + "key01": "value01" + }, + "auth": "auth data" // 请求认证信息, 通过Basic Auth方式认证 +} ``` - d、commandJobHandler:通用命令行任务Handler;业务方只需要提供命令行即可,命令及参数之间通过空格隔开;如任务参数 "ls la" 或 "pwd" 将会执行命令并输出数据; @@ -2586,10 +2606,30 @@ public void execute() { - 12、【升级】升级多项maven依赖至较新版本,如 netty、groovy、spring、spring-ai、dify 等; - 14、【优化】任务回调失败日志读写磁盘逻辑优化,解决极端情况下大文件读写内存问题; - 15、【修复】脚本任务process销毁逻辑优化,解决风险情况下脚本进程无法终止问题; -- 16、【ING】UI框架重构升级,提升交互体验; -- 17、【ING】调整资源加载逻辑,移除不必要的拦截器逻辑,提升页面加载效率; -- 18、【ING】规范API交互协议,通用响应结构体调整为Response; -- 19、【ING】Http通讯组件升级,基于接口代理方式重构; +- 16、【强化】通用HTTP任务(httpJobHandler)强化,支持更丰富请求参数设置,完整参数示例如下: +``` +{ + "url": "http://www.baidu.com", + "method": "POST", + "contentType": "application/json", + "headers": { + "header01": "value01" + }, + "cookies": { + "cookie01": "value01" + }, + "timeout": 3000, + "data": "request body data", + "form": { + "key01": "value01" + }, + "auth": "auth data" +} +``` +- 17、【ING】UI框架重构升级,提升交互体验; +- 18、【ING】调整资源加载逻辑,移除不必要的拦截器逻辑,提升页面加载效率; +- 19、【ING】规范API交互协议,通用响应结构体调整为Response; +- 20、【ING】Http通讯组件升级,基于接口代理方式重构; ### TODO LIST diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/jobhandler/SampleXxlJob.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/jobhandler/SampleXxlJob.java index 5fe777f9..383a2668 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/jobhandler/SampleXxlJob.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/jobhandler/SampleXxlJob.java @@ -2,20 +2,20 @@ package com.xxl.job.executor.jobhandler; import com.xxl.job.core.context.XxlJobHelper; import com.xxl.job.core.handler.annotation.XxlJob; +import com.xxl.tool.core.StringTool; import com.xxl.tool.gson.GsonTool; +import com.xxl.tool.http.HttpTool; +import com.xxl.tool.http.http.HttpResponse; +import com.xxl.tool.http.http.enums.ContentType; +import com.xxl.tool.http.http.enums.Header; +import com.xxl.tool.http.http.enums.Method; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.io.BufferedInputStream; import java.io.BufferedReader; -import java.io.DataOutputStream; import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -148,9 +148,9 @@ public class SampleXxlJob { @XxlJob("httpJobHandler") public void httpJobHandler() throws Exception { - // param + // param data String param = XxlJobHelper.getJobParam(); - if (param==null || param.trim().length()==0) { + if (param==null || param.trim().isEmpty()) { XxlJobHelper.log("param["+ param +"] invalid."); XxlJobHelper.handleFail(); @@ -158,113 +158,89 @@ public class SampleXxlJob { } // param parse - String url; - String method; - String data; + HttpJobParam httpJobParam = null; try { - Map paramMap = GsonTool.fromJson(param, Map.class); - url = paramMap.get("url"); - method = paramMap.get("method"); - data = paramMap.get("data"); + httpJobParam = GsonTool.fromJson(param, HttpJobParam.class); } catch (Exception e) { - XxlJobHelper.log(e); + XxlJobHelper.log(new RuntimeException("HttpJobParam parse error", e)); XxlJobHelper.handleFail(); return; } // param valid - if (url==null || url.trim().isEmpty()) { - XxlJobHelper.log("url["+ url +"] invalid."); + if (httpJobParam == null) { + XxlJobHelper.log("param parse fail."); XxlJobHelper.handleFail(); return; } - if (!isValidDomain( url)) { - XxlJobHelper.log("url["+ url +"] not allowed."); + if (StringTool.isBlank(httpJobParam.getUrl())) { + XxlJobHelper.log("url["+ httpJobParam.getUrl() +"] invalid."); XxlJobHelper.handleFail(); return; } - if (method==null || !Arrays.asList("GET", "POST").contains(method.toUpperCase())) { - XxlJobHelper.log("method["+ method +"] invalid."); + if (!isValidDomain(httpJobParam.getUrl())) { + XxlJobHelper.log("url["+ httpJobParam.getUrl() +"] not allowed."); XxlJobHelper.handleFail(); return; } - method = method.toUpperCase(); - boolean isPostMethod = method.equals("POST"); - - // request - HttpURLConnection connection = null; - BufferedReader bufferedReader = null; - try { - // connection - URL realUrl = new URL(url); - connection = (HttpURLConnection) realUrl.openConnection(); - - // connection setting - connection.setRequestMethod(method); - connection.setDoOutput(isPostMethod); - connection.setDoInput(true); - connection.setUseCaches(false); - connection.setReadTimeout(5 * 1000); - connection.setConnectTimeout(3 * 1000); - connection.setRequestProperty("connection", "Keep-Alive"); - connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); - connection.setRequestProperty("Accept-Charset", "application/json;charset=UTF-8"); - - // do connection - connection.connect(); - - // data - if (isPostMethod && data!=null && !data.trim().isEmpty()) { - DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream()); - dataOutputStream.write(data.getBytes(StandardCharsets.UTF_8)); - dataOutputStream.flush(); - dataOutputStream.close(); - } - - // valid StatusCode - int statusCode = connection.getResponseCode(); - if (statusCode != 200) { - throw new RuntimeException("Http Request StatusCode(" + statusCode + ") Invalid."); + Method method = Method.POST; + if (StringTool.isNotBlank(httpJobParam.getMethod())) { + Method methodParam = Method.valueOf(httpJobParam.getMethod().toUpperCase()); + if (methodParam == null) { + XxlJobHelper.log("method["+ httpJobParam.getMethod() +"] invalid."); + XxlJobHelper.handleFail(); + return; } - - // result - bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8)); - StringBuilder result = new StringBuilder(); - String line; - while ((line = bufferedReader.readLine()) != null) { - result.append(line); + method = methodParam; + } + ContentType contentType = ContentType.JSON; + if (StringTool.isNotBlank(httpJobParam.getContentType())) { + for (ContentType contentTypeParam : ContentType.values()) { + if (contentTypeParam.getValue().equals(httpJobParam.getContentType())) { + contentType = contentTypeParam; + break; + } } - String responseMsg = result.toString(); - - XxlJobHelper.log(responseMsg); - + } + if (httpJobParam.getTimeout() <= 0) { + XxlJobHelper.log("timeout["+ httpJobParam.getTimeout() +"] invalid."); + XxlJobHelper.handleFail(); return; + } + + // do request + try { + HttpResponse httpResponse = HttpTool.createRequest() + .url(httpJobParam.getUrl()) + .method(method) + .contentType(contentType) + .header(httpJobParam.getHeaders()) + .header(Header.USER_AGENT.getValue(), Header.DEFAULT_USER_AGENT_WIN) + .cookie(httpJobParam.getCookies()) + .body(httpJobParam.getData()) + .form(httpJobParam.getForm()) + .auth(httpJobParam.getAuth()) + .execute(); + + XxlJobHelper.log("StatusCode: " + httpResponse.statusCode()); + XxlJobHelper.log("Response:
" + httpResponse.response()); } catch (Exception e) { XxlJobHelper.log(e); - XxlJobHelper.handleFail(); - return; - } finally { - try { - if (bufferedReader != null) { - bufferedReader.close(); - } - if (connection != null) { - connection.disconnect(); - } - } catch (Exception e2) { - XxlJobHelper.log(e2); - } } - } - // domain white-list, for httpJobHandler - private static Set DOMAIN_WHITE_LIST = new HashSet(Arrays.asList( + /** + * domain white-list, for httpJobHandler + */ + private static Set DOMAIN_WHITE_LIST = Set.of( "http://www.baidu.com", "http://cn.bing.com" - )); - // valid if domain is in white-list + ); + + /** + * valid if domain is in white-list + */ private boolean isValidDomain(String url) { if (url == null || DOMAIN_WHITE_LIST.isEmpty()) { return false; @@ -277,6 +253,108 @@ public class SampleXxlJob { return false; } + /*public static void main(String[] args) { + HttpJobParam httpJobParam = new HttpJobParam(); + httpJobParam.setUrl("http://www.baidu.com"); + httpJobParam.setMethod(Method.POST.name()); + httpJobParam.setContentType(ContentType.JSON.getValue()); + httpJobParam.setHeaders(Map.of("header01", "value01")); + httpJobParam.setCookies(Map.of("cookie01", "value01")); + httpJobParam.setTimeout(3000); + httpJobParam.setData("request body data"); + httpJobParam.setForm(Map.of("form01", "value01")); + httpJobParam.setAuth("auth data"); + + logger.info(GsonTool.toJson(httpJobParam)); + }*/ + + /** + * http job param + */ + private static class HttpJobParam{ + private String url; // 请求 Url + private String method; // Method + private String contentType; // Content-Type + private Map headers; // 存储请求头 + private Map cookies; // Cookie(需要格式转换) + private int timeout; // 请求超时时间 + private String data; // 存储请求体 + private Map form; // 存储表单数据 + private String auth; // 鉴权信息 + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public Map getCookies() { + return cookies; + } + + public void setCookies(Map cookies) { + this.cookies = cookies; + } + + public int getTimeout() { + return timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public Map getForm() { + return form; + } + + public void setForm(Map form) { + this.form = form; + } + + public String getAuth() { + return auth; + } + + public void setAuth(String auth) { + this.auth = auth; + } + } + /** * 5、生命周期任务示例:任务初始化与销毁时,支持自定义相关逻辑; */