Java实现一个解析CURL脚本小工具

该工具可以将CURL脚本中的Header解析为KV Map结构;获取URL路径、请求类型;解析URL参数列表;解析Body请求体:Form表单、Raw Body、KV Body、XML/JSON/TEXT结构体等。

使用示例

获取一个http curl脚本:

curl --location --request POST 'https://cainiao-inc.com?param_1=value_1&param_2=value_2' \
--header 'Cookie: USER_COOKIE' \
--header 'Content-Type: application/json' \
--data-raw '{"appName": "link","apiId": "TEST_API","content": {"address": "Cainiao Home","city": "Hangzhou"}
}'

执行解析例子:

实现原理

实现原理很简单:基于Java正则 + 责任链设计模式,按照Curl脚本的常见语法去匹配、解析即可~

按照Curl语法结构,可以将其拆分为 5 个部分:

  • URL路径:http://cainiao.com

  • URL参数列表:?param_1=valie_1&param_2=valie_2

  • 请求方法类型: 例如 POST、GET、DELETE、PUT...... 需要正则匹配-X --request等标识符

  • Header请求头:例如 Cookie、Token、Content-Type...... 需要正则匹配-H --header等标识符

  • Body请求体:可以分为form-data/-formdata-rawdata-urlencode-d--datakvbody等。格式可能包含JSON、XML、文本、KV键值对,二进制流(暂不支持解析)等等。

具体实现

流程简图:

类关系图:

CurlParserUtil

Curl解析工具类:

public class CurlParserUtil {/*** 该方法是用来解析CURL的入口。** @param curl 输入的CURL文本字符串* @return 返回解析后生成的CURL实体对象*/public static CurlEntity parse(String curl) {CurlEntity entity = CurlEntity.builder().build();ICurlHandler<CurlEntity, String> handlerChain = CurlHandlerChain.init();// 如需扩展其他解析器,继续往链表中add即可handlerChain.next(new UrlPathHandler()).next(new UrlParamsHandler()).next(new HttpMethodHandler()).next(new HeaderHandler()).next(new HttpBodyHandler());handlerChain.handle(entity, curl);return entity;}
}

CurlEntity

解析后得到的Curl实体类(这里分了5个部分)

@Data
@Builder
public class CurlEntity {/*** URL路径*/private String url;/*** 请求方法类型*/private Method method;/*** URL参数*/private Map<String, String> urlParams;/*** header参数*/private Map<String, String> headers;/*** 请求体*/private JSONObject body;public enum Method {GET,POST,PUT,DELETE}
}

ICurlHandler

责任链链表结构定义:

public interface ICurlHandler<R, S> {ICurlHandler<CurlEntity, String> next(ICurlHandler<CurlEntity, String> handler);void handle(CurlEntity entity, String curl);
}

CurlHandlerChain

责任链载体:

public abstract class CurlHandlerChain implements ICurlHandler<CurlEntity, String> {ICurlHandler<CurlEntity, String> next;@Overridepublic ICurlHandler<CurlEntity, String> next(ICurlHandler<CurlEntity, String> handler) {this.next = handler;return this.next;}@Overridepublic abstract void handle(CurlEntity entity, String curl);/*** for subclass call*/protected void nextHandle(CurlEntity curlEntity, String curl) {if (next != null) {next.handle(curlEntity, curl);}}protected void validate(String curl) {if (StringUtils.isBlank(curl)) {throw new IllegalArgumentException("Curl script is empty");}Matcher matcher = CURL_BASIC_STRUCTURE_PATTERN.matcher(curl);if (!matcher.find()) {throw new IllegalArgumentException("Curl script is invalid");}}public static CurlHandlerChain init() {return new CurlHandlerChain() {@Overridepublic void handle(CurlEntity entity, String curl) {this.validate(curl);// 替换掉可能存在的转译curl = curl.replace("\\", "");if (next != null) {next.handle(entity, curl);}}};}public void log(Object... logParams) {// Write log for subclass extensions}
}

UrlPathHandler

URL路径解析:

public class UrlPathHandler extends CurlHandlerChain {@Overridepublic void handle(CurlEntity entity, String curl) {String url = parseUrlPath(curl);entity.setUrl(url);this.log(url);super.nextHandle(entity, curl);}/*** 该方法用于解析URL路径。** @param curl 需要解析的URL,以字符串形式给出* @return URL中的路径部分。如果找不到,将返回null*/private String parseUrlPath(String curl) {Matcher matcher = CurlPatternConstants.URL_PATH_PATTERN.matcher(curl);if (matcher.find()) {return matcher.group(1) != null ? matcher.group(1) : matcher.group(3);}return null;}@Overridepublic void log(Object... logParams) {LogPrinter.info("UrlPathHandler execute: url={}", logParams);}
}

HttpMethodHandler

请求类型解析:

public class HttpMethodHandler extends CurlHandlerChain {@Overridepublic void handle(CurlEntity entity, String curl) {CurlEntity.Method method = parseMethod(curl);entity.setMethod(method);this.log(method);super.nextHandle(entity, curl);}private CurlEntity.Method parseMethod(String curl) {Matcher matcher = CurlPatternConstants.HTTP_METHOD_PATTERN.matcher(curl);Matcher defaultMatcher = CurlPatternConstants.DEFAULT_HTTP_METHOD_PATTERN.matcher(curl);if (matcher.find()) {String method = matcher.group(1);return CurlEntity.Method.valueOf(method.toUpperCase());} else if (defaultMatcher.find()) {// 如果命令中包含 -d 或 --data,没有明确请求方法,默认为 POSTreturn CurlEntity.Method.POST;} else {// 没有明确指定请求方法,默认为 GETreturn CurlEntity.Method.GET;}}@Overridepublic void log(Object... logParams) {LogPrinter.info("HttpMethodHandler execute: method={}", logParams);}
}

UrlParamsHandler

URL参数列表解析:

public class UrlParamsHandler extends CurlHandlerChain {@Overridepublic void handle(CurlEntity entity, String curl) {String url = extractUrl(curl);Map<String, String> urlParams = parseUrlParams(url);entity.setUrlParams(urlParams);this.log(urlParams);super.nextHandle(entity, curl);}private String extractUrl(String curl) {Matcher matcher = CurlPatternConstants.URL_PARAMS_PATTERN.matcher(curl);if (matcher.find()) {return matcher.group(1);}return null;}private Map<String, String> parseUrlParams(String url) {if (StringUtils.isBlank(url)) {return Collections.emptyMap();}Map<String, String> urlParams = new HashMap<>();// 提取URL的查询参数部分String[] urlParts = url.split("\\?");if (urlParts.length > 1) {// 只处理存在查询参数的情况String query = urlParts[1];// 解析查询参数到MapString[] pairs = query.split("&");for (String pair : pairs) {int idx = pair.indexOf("=");if (idx != -1 && idx < pair.length() - 1) {String key = pair.substring(0, idx);String value = pair.substring(idx + 1);urlParams.put(key, value);} else {// 存在无值的参数时urlParams.put(pair, null);}}}return urlParams;}@Overridepublic void log(Object... logParams) {LogPrinter.info("UrlParamsHandler execute: urlParams={}", logParams);}
}

HeaderHandler

Http Header解析:

public class HeaderHandler extends CurlHandlerChain{@Overridepublic void handle(CurlEntity entity, String curl) {Map<String, String> headers = parseHeaders(curl);entity.setHeaders(headers);this.log(headers);super.nextHandle(entity, curl);}private Map<String, String> parseHeaders(String curl) {if (StringUtils.isBlank(curl)) {return Collections.emptyMap();}Matcher matcher = CurlPatternConstants.CURL_HEADERS_PATTERN.matcher(curl);Map<String, String> headers = new HashMap<>();while (matcher.find()) {String header = matcher.group(1);String[] headerKeyValue = header.split(":", 2);if (headerKeyValue.length == 2) {// 去除键和值的首尾空白字符headers.put(headerKeyValue[0].trim(), headerKeyValue[1].trim());}}return headers;}@Overridepublic void log(Object... logParams) {LogPrinter.info("HeaderHandler execute: headers={}", logParams);}
}

HttpBodyHandler

Request Body请求体解析:

  • form-data/-form

  • data-urlencode

  • data-raw

  • default/-d/--data

格式可能包含JSON、XML、文本、KV键值对,二进制流(暂不支持解析)等等。

public class HttpBodyHandler extends CurlHandlerChain {@Overridepublic void handle(CurlEntity entity, String curl) {JSONObject body = parseBody(curl);entity.setBody(body);this.log(body);super.nextHandle(entity, curl);}private JSONObject parseBody(String curl) {Matcher formMatcher = CurlPatternConstants.HTTP_FROM_BODY_PATTERN.matcher(curl);if (formMatcher.find()) {return parseFormBody(formMatcher);}Matcher urlencodeMatcher = CurlPatternConstants.HTTP_URLENCODE_BODY_PATTERN.matcher(curl);if (urlencodeMatcher.find()) {return parseUrlEncodeBody(urlencodeMatcher);}Matcher rawMatcher = CurlPatternConstants.HTTP_ROW_BODY_PATTERN.matcher(curl);if (rawMatcher.find()) {return parseRowBody(rawMatcher);}Matcher defaultMatcher = CurlPatternConstants.DEFAULT_HTTP_BODY_PATTERN.matcher(curl);if (defaultMatcher.find()) {return parseDefaultBody(defaultMatcher);}return new JSONObject();}private JSONObject parseDefaultBody(Matcher defaultMatcher) {String bodyStr = "";if (defaultMatcher.group(1) != null) {// 单引号包裹的数据bodyStr = defaultMatcher.group(1);} else if (defaultMatcher.group(2) != null) {// 双引号包裹的数据bodyStr = defaultMatcher.group(2);} else {// 无引号的数据bodyStr = defaultMatcher.group(3);}// 特殊Case: username=test&password=secretMatcher kvMatcher = CurlPatternConstants.DEFAULT_HTTP_BODY_PATTERN_KV.matcher(bodyStr);if (kvMatcher.find()) {return parseKVBody(bodyStr);}return JSONObject.parseObject(bodyStr);}private JSONObject parseKVBody(String kvBodyStr) {JSONObject json = new JSONObject();String[] pairs = kvBodyStr.split("&");for (String pair : pairs) {int idx = pair.indexOf("=");String key = URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8);String value = URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8);json.put(key, value);}return json;}private JSONObject parseFormBody(Matcher formMatcher) {JSONObject formData = new JSONObject();// 重置指针匹配的位置formMatcher.reset();while (formMatcher.find()) {// 提取表单项String formItem = formMatcher.group(1) != null ? formMatcher.group(1) : formMatcher.group(2);// 分割键和值String[] keyValue = formItem.split("=", 2);if (keyValue.length == 2) {String key = keyValue[0];String value = keyValue[1];// 检测文件字段标记// PS: 理论上文件标记字段不需要支持if (value.startsWith("@")) {// 只提取文件名,不读取文件内容formData.put(key, value.substring(1));} else {// 放入表单数据formData.put(key, value);}}}return formData;}private JSONObject parseUrlEncodeBody(Matcher urlencodeMatcher) {JSONObject urlEncodeData = new JSONObject();// 重置指针匹配的位置urlencodeMatcher.reset();while (urlencodeMatcher.find()) {// 提取键值对字符串String keyValueEncoded = urlencodeMatcher.group(1);// 分隔键和值String[] keyValue = keyValueEncoded.split("=", 2);if (keyValue.length == 2) {String key = keyValue[0];String value = keyValue[1];// 对值进行URL解码String decodedValue = URLDecoder.decode(value, StandardCharsets.UTF_8);// 存入数据到JSON对象urlEncodeData.put(key, decodedValue);}}return urlEncodeData;}private JSONObject parseRowBody(Matcher rowMatcher) {String rawData = rowMatcher.group(1);if (isXML(rawData)) {// throw new IllegalArgumentException("Curl --data-raw content cant' be XML");return xml2json(rawData);}try {return JSON.parseObject(rawData);} catch (Exception e) {throw new IllegalArgumentException("Curl --data-raw content is not a valid JSON");}}public static boolean isXML(String xmlStr) {try {DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();InputSource is = new InputSource(new StringReader(xmlStr));builder.parse(is);return true;} catch (Exception e) {return false;}}private JSONObject xml2json(String xmlStr) {try {org.json.JSONObject orgJsonObj = XML.toJSONObject(xmlStr);String jsonString = orgJsonObj.toString();return JSON.parseObject(jsonString);} catch (JSONException e) {throw new LinkConsoleException("Curl --data-raw content xml2json error", e);}}@Overridepublic void log(Object... logParams) {LogPrinter.info("HttpBodyHandler execute: body={}", logParams);}
}

CurlPatternConstants

正则匹配常量定义:

public interface CurlPatternConstants {/*** CURL基本结构校验*/Pattern CURL_BASIC_STRUCTURE_PATTERN = Pattern.compile("^curl (\\S+)");/*** URL路径匹配*/Pattern URL_PATH_PATTERN =Pattern.compile("(?:\\s|^)(?:'|\")?(https?://[^?\\s'\"]*)(?:\\?[^\\s'\"]*)?(?:'|\")?(?:\\s|$)");/*** 请求参数列表匹配*/Pattern URL_PARAMS_PATTERN = Pattern.compile("(?:\\s|^)(?:'|\")?(https?://[^\\s'\"]+)(?:'|\")?(?:\\s|$)");/*** HTTP请求方法匹配*/Pattern HTTP_METHOD_PATTERN = Pattern.compile("(?:-X|--request)\\s+(\\S+)");/*** 默认HTTP请求方法匹配*/Pattern DEFAULT_HTTP_METHOD_PATTERN = Pattern.compile(".*\\s(-d|--data|--data-binary)\\s.*");/*** 请求头匹配*/Pattern CURL_HEADERS_PATTERN = Pattern.compile("(?:-H|--header)\\s+'(.*?:.*?)'");/*** -d/--data 请求体匹配*/Pattern DEFAULT_HTTP_BODY_PATTERN = Pattern.compile("(?:--data|-d)\\s+(?:'([^']*)'|\"([^\"]*)\"|(\\S+))");Pattern DEFAULT_HTTP_BODY_PATTERN_KV = Pattern.compile("^([^=&]+=[^=&]+)(?:&[^=&]+=[^=&]+)*$");/*** --data-raw 请求体匹配*/Pattern HTTP_ROW_BODY_PATTERN = Pattern.compile("--data-raw '(.+?)'(?s)", Pattern.DOTALL);/*** --form 请求体匹配*/Pattern HTTP_FROM_BODY_PATTERN = Pattern.compile("--form\\s+'(.*?)'|-F\\s+'(.*?)'");/*** --data-urlencode 请求体匹配*/Pattern HTTP_URLENCODE_BODY_PATTERN = Pattern.compile("--data-urlencode\\s+'(.*?)'");}

有问题可以留言讨论,刷流量评论定期删除!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/30106.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【YOLOv8改进[注意力]】使用CascadedGroupAttention(2023)注意力改进c2f + 含全部代码和详细修改方式 + 手撕结构图

本文将进行在YOLOv8中使用CascadedGroupAttention注意力改进c2f 的实践,助力YOLOv8目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法。 改进前和改进后的参数对比: 目录 一 CascadedGroupAttention 二 使用CascadedGroupAttention…

反激开关电源X电容的放电电阻选型及计算

1、封装 1206 2、电压Vmax200V 3、电流Imax2A 4、功率Pmax1/4W不超过一半 阻值RC1&#xff08;根据安规快速计算&#xff09; 信息技术设备的安全&#xff0c;国家标准&#xff1a;GB4943-2011等同于UL60950 具体放电计算 初始电压为E的电容C通过R放电 V0E V0为电容上初始电压…

MySQL如何实现事务特性

目录 事务有那些特性 原子性如何实现 持久性如何实现 隔离性与一致性如何实现 事务有那些特性 事务是由MySQL的引擎 InnoDB 来实现的 事务的特性 : 原子性 不存在中间状态,要么完成,要么不完成 一致性 事务操作前和操作后,数据满足完整性的约束,数据库保持一致的状态…

SYD88xx使代码在RAM内存中执行/运行

SYD88xx使代码在RAM中执行 SYD8811/8810默认都是cache模式的&#xff0c;但是在代码首次运行的时候&#xff0c;需要将代码从flash搬到cache中执行&#xff0c;这样第一次的代码执行可能会比较慢&#xff0c;这里提供一个将需要提速的代码放到RAM中执行的方法。 对于SYD8811…

C# OCCT Winform 选中模型改变状态

选中状态设置 _context new AIS_InteractiveContext(_viewer);var selectionDrawer new Prs3d_Drawer();selectionDrawer.SetColor(Colors.Selection);selectionDrawer.SetDisplayMode(1);selectionDrawer.SetTransparency(0.1f);_context.SetSelectionStyle(selectionDrawe…

网络层 IP协议【计算机网络】【协议格式 || 分片 || 网段划分 || 子网掩码】

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 一&#xff0c;前提 二&…

java.lang.ClassNotFoundException: javafx.util.Pair的问题解决与原因详解

先说解决办法: 1、引入依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.12</version> </dependency>2、更换代码依赖地址&#xff1a; 原来依赖地址&#xff1a; import j…

企业信息资源集成-系统架构师(十二)

1、在操作系统中&#xff0c;&#xff08;&#xff09;是资源分配和管理的最小单位。 A进程 B线程 C作业 D程序段 答案&#xff1a;A 2、&#xff08;&#xff09;设计规定软件设计人员为软件组件定义正式、精确和可验证的接口规范&#xff0c;该规范应使用前提条件、后置条…

论文阅读:基于谱分析的全新早停策略

来自JMLR的一篇论文&#xff0c;https://www.jmlr.org/papers/volume24/21-1441/21-1441.pdf 这篇文章试图通过分析模型权重矩阵的频谱来解释模型&#xff0c;并在此基础上提出了一种用于早停的频谱标准。 1&#xff0c;分类难度对权重矩阵谱的影响 1.1 相关研究 在最近针对…

康谋分享 | 从CAN到CAN FD:ADTF在汽车网络中的应用

随着汽车电子技术的发展&#xff0c;车辆上配备了越来越多的电子装置&#xff0c;这些设备多采用点对点的方式通信&#xff0c;这也导致了车内存在庞大的线束。造成汽车制造和安装的困难并进一步降低汽车的配置空间&#xff0c;汽车总线逐步开始向网络化方向发展。 在此背景下…

QT绘图项目 - 汽车表盘

目录 前言: 整体代码 widget.h widget.cpp 效果演示 实现刻度文字正确排版 优化代码 达到效果 封装整理代码结构: widget.h widget.cpp 指针样式美化 优化后的指针API 效果演示 设置高速刻度为红色 优化刻度API 效果演示 速度显示优化 给内圈画上黑色 优化速度…

python子类调用其他.py文件的父类

main.py需要使用os.py中的构造类。 os.py中定义了一个Ui_MainWindow类 在main.py中定义了一个MyMainWindow子类&#xff0c;传入两个父类的变量名 super(Ui_MainWindow, self).__init__()super() super() 是一个内置函数&#xff0c;用于返回一个代表父类的对象&#xff0c;…

2024/6/19 英语每日一段

From this story, one might imagine Warwick to be opposed to “killing in the name of conservation”; in fact, though, he’s conflicted. Conservation “is really complicated,” he writes. “There is an old saying that anyone who gives you a simple answer to…

探索磁力搜索引擎:互联网资源获取的新视角

在当今数字化社会中&#xff0c;寻找和获取网络资源变得更加便捷和多样化。磁力搜索引擎作为这一趋势的一部分&#xff0c;提供了一种新颖而有效的方法来定位和获取用户所需的文件、媒体和其他数字内容。本文将深入探讨磁力搜索引擎的工作原理、使用场景及其在网络文化中的影响…

最快安装zabbix

部署zabbix 6.x 建议使用红帽系统。 https://download.rockylinux.org/pub/rocky/8/isos/x86_64/Rocky-8.9-x86_64-minimal.iso1> 配置安装yum源 [rootzabbix ~]# yum install https://mirrors.huaweicloud.com/zabbix/zabbix/6.2/rhel/8/x86_64/zabbix-release-6.2-3.el8…

精度丢失引起的支付失败问题

问题描述 在提交订单时候&#xff0c;输入充值金额和优惠码&#xff0c;后台会返回具体的订单信息&#xff0c;如下图&#xff0c;支付金额应该是1 * (1 - 0.09) 0.91&#xff08;这个是理想状态&#xff09;&#xff0c;但是表单显示的是0.90999997&#xff0c; 然后点击确…

架构师篇-1、总体架构设计

业务架构哲学本质 定位&#xff1a;赋予业务架构设计能力&#xff0c;具备业务架构设计思维模型&#xff0c;掌握业务架构哲学本质&#xff0c;形成以不变应万变的业务架构设计能力。 架构师所需要的能力&#xff1a; 带领业务成功通过框架思维赋能业务架构师知识体系构建掌…

HDU——2090.算菜价、2091.空心三角形、2093.考试排名

2090.算菜价 题目描述 Problem - 2090 Problem Description 妈妈每天都要出去买菜&#xff0c;但是回来后&#xff0c;兜里的钱也懒得数一数&#xff0c;到底花了多少钱真是一笔糊涂帐。现在好了&#xff0c;作为好儿子&#xff08;女儿&#xff09;的你可以给她用程序算一…

Adobe XD是否收费?试试这几款超值的免费软件吧!

Adobe XD是一站式的 UX/UI 设计平台&#xff0c;设计师可以使用Adobe XD完成移动应用app界面设计、网页设计、原型设计等。Adobe XD也是一款结合原型和设计&#xff0c;提供工业性能的跨平台设计产品。而Adobebe。 XD跨平台的特点得到了很好的弥补 Sketch 没有 Windows 版本的缺…

网安人必备!开源网络安全工具TOP 10(附下载地址)

工欲善其事&#xff0c;必先利其器。对于广大的网络安全从业者&#xff0c;以及未来想要从事网络安全的人来说&#xff0c;选择并善用合适的网络安全工具&#xff0c;能有效提升工作效率。 开源网络安全工具之所以能够在众多安全解决方案中脱颖而出&#xff0c;不仅是因为它们…