java-curl
java-curl copied to clipboard
可以实现对 cURL 解析吗?
解析是什么意思,我这个就是可以在java程序里用字符串格式的curl命令来发起各种http请求
Sorry ,我想表达的意思其实是,比如我在浏览器或者 Postman 上将一个 cURL 格式的字符串导出后,在 Java 端可以直接执行 Http 请求。
例如:
curl --location --request POST '127.0.0.1/manage/xx/xxx' \ --header 'Content-Type: application/json' \ --data-raw '{ "to_business_id": 4 }'
可以直接请求(伪代码):
String result = Curl.action("curl --location --request GET '127.0.0.1/manage/xx/xxx'",String.class);
可以的,兼容大部分常用命令和开关
拉下来尝试了一下,好像没有解析的 API ~ 我核心诉求是自己懒得解析输入的 cURL 了。
可能需要一个 CUrl cUrl = CurlHelper.parse("curl --location --request GET '127.0.0.1/manage/xx/xxx'");
🥲
把所有参数分割按空格分割然后用opt依次传入即可: new CUrl().opt('127.0.0.1/manage/xx/xxx', '--location', '--request', 'GET') .exec(null)
比方说解析出各种参数返回一个map
我有同样的需要,所以我写了一个工具类。用来将Postman、Chrome、Charles生成的curl转为一个数组,并且这个数据可以直接作为参数调用本库。
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
public class CurlUtils {
/**
* this code copy and update from {@link com.roxstudio.utils.CUrl.Util}
*/
private final static class Util {
public static <K, V, M extends Map<K, V>> M mapPut(M map, Object... keyValuePairs) {
if ((keyValuePairs.length & 1) != 0)
throw new IllegalArgumentException("the number of keyValuePairs arguments must be odd");
for (int i = 0, n = keyValuePairs.length; i < n; i += 2) {
map.put((K) keyValuePairs[i], (V) keyValuePairs[i + 1]);
}
return map;
}
}
/**
* this code copy and update from {@link com.roxstudio.utils.CUrl#optMap}
*/
private static final Map<String, Integer> optMap = Util.mapPut(new LinkedHashMap<String, Integer>(),
"-E", 32,
"--cert", 32, // <certificate[:password]> Client certificate file and password
"--compressed", 1, // Request compressed response (using deflate or gzip)
"--connect-timeout", 2, // SECONDS Maximum time allowed for connection
"-b", 3,
"--cookie", 3, // STRING/FILE Read cookies from STRING/FILE (H)
"-c", 4,
"--cookie-jar", 4, // FILE Write cookies to FILE after operation (H)
"-d", 5,
"--data", 5, // DATA HTTP POST data (H)
"--data-ascii", 5, // DATA HTTP POST ASCII data (H)
"--data-raw", 51, // DATA HTTP POST raw data (H)
"--data-binary", 52, // DATA HTTP POST binary data (H)
"--data-urlencode", 53, // DATA HTTP POST data url encoded (H)
"-D", 6,
"--dump-header", 6, // FILE Write the headers to FILE
"-F", 7,
"--form", 7, // CONTENT Specify HTTP multipart POST data (H)
"--form-string", 71, // STRING Specify HTTP multipart POST data (H)
"-G", 8,
"--get", 8, // Send the -d data with a HTTP GET (H)
"-H", 10,
"--header", 10, // LINE Pass custom header LINE to server (H)
"-I", 11,
"--head", 11, // Show document info only
// "--ignore-content-length", 12, // Ignore the HTTP Content-Length header
"-k", 31,
"--insecure", 31, // Allow insecure server connections when using SSL
"-L", 13,
"--location", 13, // Follow redirects (H)
"-m", 14,
"--max-time", 14, // SECONDS Maximum time allowed for the transfer
// "--no-keepalive", 15, // Disable keepalive use on the connection
"-o", 16,
"--output", 16, // FILE Write to FILE instead of stdout
"-x", 17,
"--proxy", 17, // [PROTOCOL://]HOST[:PORT] Use proxy on given port
"-U", 18,
"--proxy-user", 18, // USER[:PASSWORD] Proxy user and password
"-e", 19,
"--referer", 19, // Referer URL (H)
"--retry", 20, // NUM Retry request NUM times if transient problems occur
"--retry-delay", 21, // SECONDS Wait SECONDS between retries
"--retry-max-time", 22, // SECONDS Retry only within this period
"-s", 23,
"--silent", 23, // Silent mode (don't output anything)
"--stderr", 24, // FILE Where to redirect stderr (use "-" for stdout)
"-u", 28,
"--user", 28, // USER[:PASSWORD] Server user and password
"--url", 25, // URL URL to work with
"-A", 26,
"--user-agent", 26, // STRING Send User-Agent STRING to server (H)
"-X", 27,
"--request", 27, // COMMAND Specify request command to use
"--x-max-download", 29, // BYTES Maximum bytes allowed for the download
"--x-tags", 30, // DATA extra key-value pairs, storage only
"", 0 // placeholder
);
/**
* 解析 postman、Chrome、Charles 导出的curl.
*
* @param curl postman、Chrome 或 Charles 导出的curl.
* @return 可以参数的数组
*/
public static String[] resolver(String curl) {
if (curl == null || "".equals(curl)) {
throw new IllegalArgumentException("curl can't be empty!");
}
List<String> opts = new ArrayList<>();//记录所有的curl参数选项(包括字符串“curl”)。
List<Character> currentOptCharArray = new ArrayList<>();//记录当前处理的参数选项的字符集合。
char spaceDelimiter = ' ';//空格分隔符。postman、Chrome、Charles 都会将其用作分隔符。
char singleQuoteDelimiter = '\'';//单引号分隔符。postman、Chrome 会将其用作分隔符。
char doubleQuoteDelimiter = '"';//双引号分隔符。Charles 会将其用作分隔符。
//当前使用的分割符,它可以为空格单引号或者双引号。当单引号出现时,它匹配下一个单引号,两单引号之间的空格不能作为分隔符。双引号同理。
char currentDelimiter = spaceDelimiter;
char previousChar = ' ';//上一个字符,如果上一个字符时‘\’,则当前字符为分隔符时也不结束当前opt的处理,而是将这个分隔符当成普通字符处理
char[] charCurl = curl.toCharArray();
for (char c : charCurl) {
//当前不活跃的分隔符,当“当前使用的分隔符currentDelimiter”为spaceDelimiter时,其为singleQuoteDelimiter。否则相反。
char[] anotherDelimiterChar = getAnotherDelimiterChar(currentDelimiter, spaceDelimiter, singleQuoteDelimiter, doubleQuoteDelimiter);
//当前字符为分隔符时,可能为某个参数选择的开始或结束部分。
//这里不区分是参数选项的开始或结束部分,统一将其作为一个参数选项放到最终结果中。
if (currentDelimiter == c && previousChar != '\\') {
String opt = currentOptCharArray.stream()
.map(String::valueOf)
.collect(Collectors.joining());
opts.add(opt);
currentOptCharArray.clear();
} else if (checkCurCharIsAnotherDelimiterChar(c, anotherDelimiterChar)) {
if (currentOptCharArray.isEmpty()) {
currentDelimiter = c;
} else {
currentOptCharArray.add(c);
}
} else {
currentOptCharArray.add(c);
}
previousChar = c;
}
opts = opts.stream()
.filter(Objects::nonNull)
.map(String::trim)
.map(s -> s.replaceAll("\\\\\n", ""))
.filter(i -> i.length() > 0)
.collect(Collectors.toList());
List<String> needRemove = new ArrayList<>();
String previousOpt = "";
for (String opt : opts) {
if (previousOpt.startsWith("-") && optMap.containsKey(previousOpt)) {
//保留
} else if (opt.startsWith("http")) {
//保留
} else if (opt.startsWith("-") && optMap.containsKey(opt)) {
//保留
} else {
//移除
needRemove.add(opt);
}
previousOpt = opt;
}
opts.removeIf(needRemove::contains);
return opts.toArray(new String[0]);
}
private static boolean checkCurCharIsAnotherDelimiterChar(char c, char[] antherDelimiterChar) {
return c == antherDelimiterChar[0] || c == antherDelimiterChar[1];
}
private static char[] getAnotherDelimiterChar(char c, char spaceDelimiter, char singleQuoteDelimiter, char doubleQuoteDelimiter) {
if (c == spaceDelimiter) {
return new char[]{singleQuoteDelimiter, doubleQuoteDelimiter};
} else if (c == singleQuoteDelimiter) {
return new char[]{spaceDelimiter, doubleQuoteDelimiter};
} else {
return new char[]{spaceDelimiter, singleQuoteDelimiter};
}
}
}
我是这么使用的:
String curlStr = "...";
String[] opts = CurlUtils.resolver(curlStr);
CUrl curl = new CUrl().opt(opts);
curl.exec();
return curl;
我们直接从Postman、Chrome或Charles中复制curl后,粘贴到String curlStr = "...";
中的...
处。
注意,...
外的两个双引号是必须的,有了它们在IDEA中进行粘贴时,IDE会帮我合理的处理转义字符。
(其实就是相当于我们将复制来的的curl粘贴到String curlStr = "";
的两个双引号内)
这里提供3个参考的curl格式:
private static String chromeCurl = "curl 'https://id.xiapibuy.com/api/v4/item/get?itemid=4656131375&shopid=59763733' \\\n" +
" -H 'authority: id.xiapibuy.com' \\\n" +
" -H 'accept: application/json' \\\n" +
" -H 'accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' \\\n" +
" -H 'af-ac-enc-dat: AAcyLjMuMi00AAABg6IB9VoAAAxPAlcAAAAAAAAAALUc1tfPtx2eNZ+lQGEPXp3+N/SdzqNmxlp1L4tff1r27p8SwpcqlWoElPRl6ekEWeJsUptHCecgZgZUJNkMdyN9VJJ4Fcmn7nW9/iudAovi3Q4KeZFjs4yw8pGWNnYQjtmnppZkfx9s4w5mdq+xn6n9CtBqjYL9eKtscmx0v9UESe7UD5Fjs4yw8pGWNnYQjtmnppaeKwVmxFcF4ObDBrVINAKBdpYoBoaFxN4DV/pDl++L3/+NBeKB3wKlJvciBdWBBvaaeijPYf2G85HzJCJhO1xsKL1Rr43EU9rxBiNpNsgWiwTNue0ItFTg/V6S7yZ8b+URul/bNcp2Sur50wYMwSDikzRUuI9VU/LDpdQRLTm64iSmZ5ThVbxHE3bdSJ9U0k5djSR7fl8kZiNFp11d12JqI4GTqcIATPt0rYY/lg4GZoZ/6ktmA7MUhEIUj6kljFqZodbQEboXldfnVQFaMWIRrUq2io6kjRkGnw5JC7ja0YFovT2tvG0p7cDHKgUGL93c/eepLj1lWtbHvNydwzvOa8ZStWbkuVsfU1NJsDNWgQw2vl6G5BYjnlVUlNQzjfl60IFyefQS4QYdAcZKZtV5I4GTqcIATPt0rYY/lg4GZj+Nb4u1WHdUbCpXPApg4mao52Taa8i2RDDJAlpz1hDHJ3sXY0pNMunSQQvtExUbtN8KGuKS7t75OG7HfrT1pgMwhI+YiNH/GP07SAnecP+UZMBWDhT2yZm1nTpH6VAmUXk2o2vAiFhae2cy1xcnWzIzd2M3mBXX19lEIVCN2i+VJsmnz6s86WzMSRw/5y6a0g==' \\\n" +
" -H 'cache-control: no-cache' \\\n" +
" -H 'content-type: application/json' \\\n" +
" -H 'cookie: SPC_SI=3hs0YwAAAABjZENnSjgzZ5bfrQAAAAAAaHBRWEJ0QWQ=; SPC_F=hBrQhw0KNoxgTaQfmckmMB4htCvkC4Dh; REC_T_ID=76a50dcf-43ba-11ed-b7d1-2cea7fac4cc4; SPC_R_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_R_T_IV=R2JwaXZIQk5OemlSRm9pcA==; SPC_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_T_IV=R2JwaXZIQk5OemlSRm9pcA==; csrftoken=TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k; _gcl_au=1.1.543085384.1664870366; _med=refer; __LOCALE__null=ID' \\\n" +
" -H 'pragma: no-cache' \\\n" +
" -H 'referer: https://id.xiapibuy.com/Wardah-UV-Shield-Essential-Sunscreen-Gel-SPF-30-PA-40-ml-i.59763733.4656131375?sp_atk=b8bd5424-60fe-4e23-8c87-412b464083d1&xptdk=b8bd5424-60fe-4e23-8c87-412b464083d1' \\\n" +
" -H 'sec-ch-ua: \"Google Chrome\";v=\"105\", \"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"105\"' \\\n" +
" -H 'sec-ch-ua-mobile: ?0' \\\n" +
" -H 'sec-ch-ua-platform: \"macOS\"' \\\n" +
" -H 'sec-fetch-dest: empty' \\\n" +
" -H 'sec-fetch-mode: cors' \\\n" +
" -H 'sec-fetch-site: same-origin' \\\n" +
" -H 'sz-token: false||MTAwMDI=' \\\n" +
" -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' \\\n" +
" -H 'x-api-source: pc' \\\n" +
" -H 'x-csrftoken: TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k' \\\n" +
" -H 'x-requested-with: XMLHttpRequest' \\\n" +
" -H 'x-shopee-language: id' \\\n" +
" -H 'x-sz-sdk-version: 2.3.2-4' \\\n" +
" --compressed";
private static String postmanCurl = "curl --location --request GET 'https://id.xiapibuy.com/api/v4/item/get?itemid=4656131375&shopid=59763733' \\\n" +
"--header 'authority: id.xiapibuy.com' \\\n" +
"--header 'accept: application/json' \\\n" +
"--header 'accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' \\\n" +
"--header 'af-ac-enc-dat: AAcyLjMuMi00AAABg6IB9VoAAAxPAlcAAAAAAAAAALUc1tfPtx2eNZ+lQGEPXp3+N/SdzqNmxlp1L4tff1r27p8SwpcqlWoElPRl6ekEWeJsUptHCecgZgZUJNkMdyN9VJJ4Fcmn7nW9/iudAovi3Q4KeZFjs4yw8pGWNnYQjtmnppZkfx9s4w5mdq+xn6n9CtBqjYL9eKtscmx0v9UESe7UD5Fjs4yw8pGWNnYQjtmnppaeKwVmxFcF4ObDBrVINAKBdpYoBoaFxN4DV/pDl++L3/+NBeKB3wKlJvciBdWBBvaaeijPYf2G85HzJCJhO1xsKL1Rr43EU9rxBiNpNsgWiwTNue0ItFTg/V6S7yZ8b+URul/bNcp2Sur50wYMwSDikzRUuI9VU/LDpdQRLTm64iSmZ5ThVbxHE3bdSJ9U0k5djSR7fl8kZiNFp11d12JqI4GTqcIATPt0rYY/lg4GZoZ/6ktmA7MUhEIUj6kljFqZodbQEboXldfnVQFaMWIRrUq2io6kjRkGnw5JC7ja0YFovT2tvG0p7cDHKgUGL93c/eepLj1lWtbHvNydwzvOa8ZStWbkuVsfU1NJsDNWgQw2vl6G5BYjnlVUlNQzjfl60IFyefQS4QYdAcZKZtV5I4GTqcIATPt0rYY/lg4GZj+Nb4u1WHdUbCpXPApg4mao52Taa8i2RDDJAlpz1hDHJ3sXY0pNMunSQQvtExUbtN8KGuKS7t75OG7HfrT1pgMwhI+YiNH/GP07SAnecP+UZMBWDhT2yZm1nTpH6VAmUXk2o2vAiFhae2cy1xcnWzIzd2M3mBXX19lEIVCN2i+VJsmnz6s86WzMSRw/5y6a0g==' \\\n" +
"--header 'cache-control: no-cache' \\\n" +
"--header 'content-type: application/json' \\\n" +
"--header 'cookie: SPC_SI=3hs0YwAAAABjZENnSjgzZ5bfrQAAAAAAaHBRWEJ0QWQ=; SPC_F=hBrQhw0KNoxgTaQfmckmMB4htCvkC4Dh; REC_T_ID=76a50dcf-43ba-11ed-b7d1-2cea7fac4cc4; SPC_R_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_R_T_IV=R2JwaXZIQk5OemlSRm9pcA==; SPC_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_T_IV=R2JwaXZIQk5OemlSRm9pcA==; csrftoken=TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k; _gcl_au=1.1.543085384.1664870366; _med=refer; __LOCALE__null=ID; SPC_R_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_R_T_IV=R2JwaXZIQk5OemlSRm9pcA==; SPC_SI=3hs0YwAAAABjZENnSjgzZ5bfrQAAAAAAaHBRWEJ0QWQ=; SPC_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_T_IV=R2JwaXZIQk5OemlSRm9pcA==' \\\n" +
"--header 'pragma: no-cache' \\\n" +
"--header 'referer: https://id.xiapibuy.com/Wardah-UV-Shield-Essential-Sunscreen-Gel-SPF-30-PA-40-ml-i.59763733.4656131375?sp_atk=b8bd5424-60fe-4e23-8c87-412b464083d1&xptdk=b8bd5424-60fe-4e23-8c87-412b464083d1' \\\n" +
"--header 'sec-ch-ua: \"Google Chrome\";v=\"105\", \"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"105\"' \\\n" +
"--header 'sec-ch-ua-mobile: ?0' \\\n" +
"--header 'sec-ch-ua-platform: \"macOS\"' \\\n" +
"--header 'sec-fetch-dest: empty' \\\n" +
"--header 'sec-fetch-mode: cors' \\\n" +
"--header 'sec-fetch-site: same-origin' \\\n" +
"--header 'sz-token: false||MTAwMDI=' \\\n" +
"--header 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' \\\n" +
"--header 'x-api-source: pc' \\\n" +
"--header 'x-csrftoken: TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k' \\\n" +
"--header 'x-requested-with: XMLHttpRequest' \\\n" +
"--header 'x-shopee-language: id' \\\n" +
"--header 'x-sz-sdk-version: 2.3.2-4'";
private static String charlesUrl = "curl -H \"Host: id.xiapibuy.com\" -H \"Cookie: __LOCALE__null=ID; SPC_R_T_ID=ALV16yYYrJ954Cnd/qwq4ci/BJ9pEqXfZiOmxynSt3Fo/sBMtsXLmlfIV4vsCMvSB3suRczaBlCwhX00guo3dchuKO97Sjtk9V3yqqDwhv3Dtd8e6iLj2pjfYSi2aPImipqa47kYl7y/OO8pWfPg3j4ae9hGX5Q5pehCLg+Y2JU=; SPC_R_T_IV=RDB0YWZuaDdoYzlUQjl4TQ==; SPC_T_ID=ALV16yYYrJ954Cnd/qwq4ci/BJ9pEqXfZiOmxynSt3Fo/sBMtsXLmlfIV4vsCMvSB3suRczaBlCwhX00guo3dchuKO97Sjtk9V3yqqDwhv3Dtd8e6iLj2pjfYSi2aPImipqa47kYl7y/OO8pWfPg3j4ae9hGX5Q5pehCLg+Y2JU=; SPC_T_IV=RDB0YWZuaDdoYzlUQjl4TQ==; SPC_SI=5ho0YwAAAABwYTcwNFVsamdtsAAAAAAAeUVRUUE0VjA=; SPC_F=jCpKTv12KM6sXu0MdxxNCPdZ1f0NVTPC; REC_T_ID=db8d158c-43c7-11ed-a908-9440c93f746c; _gcl_au=1.1.2039763134.1664876118; csrftoken=TVdf0bEKtUAwodW82Xrs1lMkocbjUjMR; _QPWSDCXHZQA=a9e781f2-3192-47b2-df32-66b9f8b03504\" -H \"sec-ch-ua: \\\"Chromium\\\";v=\\\"104\\\", \\\" Not A;Brand\\\";v=\\\"99\\\", \\\"Yandex\\\";v=\\\"22\\\"\" -H \"sec-ch-ua-mobile: ?0\" -H \"x-sz-sdk-version: 2.3.2-4\" -H \"content-type: application/json\" -H \"accept: application/json\" -H \"x-shopee-language: id\" -H \"x-requested-with: XMLHttpRequest\" -H \"af-ac-enc-dat: AAcyLjMuMi00AAABg6KA2rMAAAxxAl0AAAAAAAAAALUc1tfqbJnquBjued3SPfDPNjZcwE5Y9CZDRAouDOTxYI6c0JcqlWoElPRl6ekEWeJsUptHCecgZgZUJNkMdyN9VJJ4Fcmn7nW9/iudAovi3Q4KeZFjs4yw8pGWNnYQjtmnppZkfx9s4w5mdq+xn6n9CtBqjYL9eKtscmx0v9UESe7UD5Fjs4yw8pGWNnYQjtmnppaeKwVmxFcF4ObDBrVINAKBq33VS+JVwnZ0HZWVGjz0oP+NBeKB3wKlJvciBdWBBvaaeijPYf2G85HzJCJhO1xsu7KKtg+IfFmuwykkfhJDjR2bU6BiP4jbbVh1cX3MKN0734doRzrCsZdk/6poJelfmVG2rUT03+NpNuFFxwWbIq+H8FsUC1SsOYA7uQssm6UlVhQnezi7GN9B49To0imbwzU6ZAIWKr3Tsiwkxq+NZB8hRld2WqENNTV9bukfQJwRul/bNcp2Sur50wYMwSDikzRUuI9VU/LDpdQRLTm64vGVFtzkzh3gjuLxgwquIESRZr8EptQTXXHI8QHpIBMd8cK6D+mS+izuW4fUEsbihmJFJkfOAnBywenZjD51w1BpGoHGvTBYivEZkbKzdr3CwzU6ZAIWKr3Tsiwkxq+NZBYm5PkcTch/SjQhPcsffZqfgIsuafgATPq8Uo4cqq7ZYeSCB+mwNST62/azLCJvzRryBkGqp2S6ViIMDM/xlofpdRoO+1stSFfsgxQ/QhMqhkWt0Sybvjx5xWkhiT5NjZY0NKdgbIimpnHd5HDrpP3ISU9CGiXXdY2/Gg2klBRMPyZ1BaM9cKQ3ySAPn6+ZjA==\" -H \"x-api-source: pc\" -H \"user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.114 YaBrowser/22.9.1.1081 Yowser/2.5 Safari/537.36\" -H \"x-csrftoken: TVdf0bEKtUAwodW82Xrs1lMkocbjUjMR\" -H \"sec-ch-ua-platform: \\\"macOS\\\"\" -H \"sec-fetch-site: same-origin\" -H \"sec-fetch-mode: cors\" -H \"sec-fetch-dest: empty\" -H \"referer: https://id.xiapibuy.com/Wardah-UV-Shield-Essential-Sunscreen-Gel-SPF-30-PA-40-ml-i.59763733.4656131375?sp_atk=b8bd5424-60fe-4e23-8c87-412b464083d1&xptdk=b8bd5424-60fe-4e23-8c87-412b464083d1\" -H \"accept-language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6\" --compressed \"https://id.xiapibuy.com/api/v4/item/get?itemid=4656131375&shopid=59763733\"";
不错不错!
我有同样的需要,所以我写了一个工具类。用来将Postman、Chrome、Charles生成的curl转为一个数组,并且这个数据可以直接作为参数调用本库。
import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; public class CurlUtils { /** * this code copy and update from {@link com.roxstudio.utils.CUrl.Util} */ private final static class Util { public static <K, V, M extends Map<K, V>> M mapPut(M map, Object... keyValuePairs) { if ((keyValuePairs.length & 1) != 0) throw new IllegalArgumentException("the number of keyValuePairs arguments must be odd"); for (int i = 0, n = keyValuePairs.length; i < n; i += 2) { map.put((K) keyValuePairs[i], (V) keyValuePairs[i + 1]); } return map; } } /** * this code copy and update from {@link com.roxstudio.utils.CUrl#optMap} */ private static final Map<String, Integer> optMap = Util.mapPut(new LinkedHashMap<String, Integer>(), "-E", 32, "--cert", 32, // <certificate[:password]> Client certificate file and password "--compressed", 1, // Request compressed response (using deflate or gzip) "--connect-timeout", 2, // SECONDS Maximum time allowed for connection "-b", 3, "--cookie", 3, // STRING/FILE Read cookies from STRING/FILE (H) "-c", 4, "--cookie-jar", 4, // FILE Write cookies to FILE after operation (H) "-d", 5, "--data", 5, // DATA HTTP POST data (H) "--data-ascii", 5, // DATA HTTP POST ASCII data (H) "--data-raw", 51, // DATA HTTP POST raw data (H) "--data-binary", 52, // DATA HTTP POST binary data (H) "--data-urlencode", 53, // DATA HTTP POST data url encoded (H) "-D", 6, "--dump-header", 6, // FILE Write the headers to FILE "-F", 7, "--form", 7, // CONTENT Specify HTTP multipart POST data (H) "--form-string", 71, // STRING Specify HTTP multipart POST data (H) "-G", 8, "--get", 8, // Send the -d data with a HTTP GET (H) "-H", 10, "--header", 10, // LINE Pass custom header LINE to server (H) "-I", 11, "--head", 11, // Show document info only // "--ignore-content-length", 12, // Ignore the HTTP Content-Length header "-k", 31, "--insecure", 31, // Allow insecure server connections when using SSL "-L", 13, "--location", 13, // Follow redirects (H) "-m", 14, "--max-time", 14, // SECONDS Maximum time allowed for the transfer // "--no-keepalive", 15, // Disable keepalive use on the connection "-o", 16, "--output", 16, // FILE Write to FILE instead of stdout "-x", 17, "--proxy", 17, // [PROTOCOL://]HOST[:PORT] Use proxy on given port "-U", 18, "--proxy-user", 18, // USER[:PASSWORD] Proxy user and password "-e", 19, "--referer", 19, // Referer URL (H) "--retry", 20, // NUM Retry request NUM times if transient problems occur "--retry-delay", 21, // SECONDS Wait SECONDS between retries "--retry-max-time", 22, // SECONDS Retry only within this period "-s", 23, "--silent", 23, // Silent mode (don't output anything) "--stderr", 24, // FILE Where to redirect stderr (use "-" for stdout) "-u", 28, "--user", 28, // USER[:PASSWORD] Server user and password "--url", 25, // URL URL to work with "-A", 26, "--user-agent", 26, // STRING Send User-Agent STRING to server (H) "-X", 27, "--request", 27, // COMMAND Specify request command to use "--x-max-download", 29, // BYTES Maximum bytes allowed for the download "--x-tags", 30, // DATA extra key-value pairs, storage only "", 0 // placeholder ); /** * 解析 postman、Chrome、Charles 导出的curl. * * @param curl postman、Chrome 或 Charles 导出的curl. * @return 可以参数的数组 */ public static String[] resolver(String curl) { if (curl == null || "".equals(curl)) { throw new IllegalArgumentException("curl can't be empty!"); } List<String> opts = new ArrayList<>();//记录所有的curl参数选项(包括字符串“curl”)。 List<Character> currentOptCharArray = new ArrayList<>();//记录当前处理的参数选项的字符集合。 char spaceDelimiter = ' ';//空格分隔符。postman、Chrome、Charles 都会将其用作分隔符。 char singleQuoteDelimiter = '\'';//单引号分隔符。postman、Chrome 会将其用作分隔符。 char doubleQuoteDelimiter = '"';//双引号分隔符。Charles 会将其用作分隔符。 //当前使用的分割符,它可以为空格单引号或者双引号。当单引号出现时,它匹配下一个单引号,两单引号之间的空格不能作为分隔符。双引号同理。 char currentDelimiter = spaceDelimiter; char previousChar = ' ';//上一个字符,如果上一个字符时‘\’,则当前字符为分隔符时也不结束当前opt的处理,而是将这个分隔符当成普通字符处理 char[] charCurl = curl.toCharArray(); for (char c : charCurl) { //当前不活跃的分隔符,当“当前使用的分隔符currentDelimiter”为spaceDelimiter时,其为singleQuoteDelimiter。否则相反。 char[] anotherDelimiterChar = getAnotherDelimiterChar(currentDelimiter, spaceDelimiter, singleQuoteDelimiter, doubleQuoteDelimiter); //当前字符为分隔符时,可能为某个参数选择的开始或结束部分。 //这里不区分是参数选项的开始或结束部分,统一将其作为一个参数选项放到最终结果中。 if (currentDelimiter == c && previousChar != '\\') { String opt = currentOptCharArray.stream() .map(String::valueOf) .collect(Collectors.joining()); opts.add(opt); currentOptCharArray.clear(); } else if (checkCurCharIsAnotherDelimiterChar(c, anotherDelimiterChar)) { if (currentOptCharArray.isEmpty()) { currentDelimiter = c; } else { currentOptCharArray.add(c); } } else { currentOptCharArray.add(c); } previousChar = c; } opts = opts.stream() .filter(Objects::nonNull) .map(String::trim) .map(s -> s.replaceAll("\\\\\n", "")) .filter(i -> i.length() > 0) .collect(Collectors.toList()); List<String> needRemove = new ArrayList<>(); String previousOpt = ""; for (String opt : opts) { if (previousOpt.startsWith("-") && optMap.containsKey(previousOpt)) { //保留 } else if (opt.startsWith("http")) { //保留 } else if (opt.startsWith("-") && optMap.containsKey(opt)) { //保留 } else { //移除 needRemove.add(opt); } previousOpt = opt; } opts.removeIf(needRemove::contains); return opts.toArray(new String[0]); } private static boolean checkCurCharIsAnotherDelimiterChar(char c, char[] antherDelimiterChar) { return c == antherDelimiterChar[0] || c == antherDelimiterChar[1]; } private static char[] getAnotherDelimiterChar(char c, char spaceDelimiter, char singleQuoteDelimiter, char doubleQuoteDelimiter) { if (c == spaceDelimiter) { return new char[]{singleQuoteDelimiter, doubleQuoteDelimiter}; } else if (c == singleQuoteDelimiter) { return new char[]{spaceDelimiter, doubleQuoteDelimiter}; } else { return new char[]{spaceDelimiter, singleQuoteDelimiter}; } } }
我是这么使用的:
String curlStr = "..."; String[] opts = CurlUtils.resolver(curlStr); CUrl curl = new CUrl().opt(opts); curl.exec(); return curl;
我们直接从Postman、Chrome或Charles中复制curl后,粘贴到
String curlStr = "...";
中的...
处。 注意,...
外的两个双引号是必须的,有了它们在IDEA中进行粘贴时,IDE会帮我合理的处理转义字符。 (其实就是相当于我们将复制来的的curl粘贴到String curlStr = "";
的两个双引号内)这里提供3个参考的curl格式:
private static String chromeCurl = "curl 'https://id.xiapibuy.com/api/v4/item/get?itemid=4656131375&shopid=59763733' \\\n" + " -H 'authority: id.xiapibuy.com' \\\n" + " -H 'accept: application/json' \\\n" + " -H 'accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' \\\n" + " -H 'af-ac-enc-dat: AAcyLjMuMi00AAABg6IB9VoAAAxPAlcAAAAAAAAAALUc1tfPtx2eNZ+lQGEPXp3+N/SdzqNmxlp1L4tff1r27p8SwpcqlWoElPRl6ekEWeJsUptHCecgZgZUJNkMdyN9VJJ4Fcmn7nW9/iudAovi3Q4KeZFjs4yw8pGWNnYQjtmnppZkfx9s4w5mdq+xn6n9CtBqjYL9eKtscmx0v9UESe7UD5Fjs4yw8pGWNnYQjtmnppaeKwVmxFcF4ObDBrVINAKBdpYoBoaFxN4DV/pDl++L3/+NBeKB3wKlJvciBdWBBvaaeijPYf2G85HzJCJhO1xsKL1Rr43EU9rxBiNpNsgWiwTNue0ItFTg/V6S7yZ8b+URul/bNcp2Sur50wYMwSDikzRUuI9VU/LDpdQRLTm64iSmZ5ThVbxHE3bdSJ9U0k5djSR7fl8kZiNFp11d12JqI4GTqcIATPt0rYY/lg4GZoZ/6ktmA7MUhEIUj6kljFqZodbQEboXldfnVQFaMWIRrUq2io6kjRkGnw5JC7ja0YFovT2tvG0p7cDHKgUGL93c/eepLj1lWtbHvNydwzvOa8ZStWbkuVsfU1NJsDNWgQw2vl6G5BYjnlVUlNQzjfl60IFyefQS4QYdAcZKZtV5I4GTqcIATPt0rYY/lg4GZj+Nb4u1WHdUbCpXPApg4mao52Taa8i2RDDJAlpz1hDHJ3sXY0pNMunSQQvtExUbtN8KGuKS7t75OG7HfrT1pgMwhI+YiNH/GP07SAnecP+UZMBWDhT2yZm1nTpH6VAmUXk2o2vAiFhae2cy1xcnWzIzd2M3mBXX19lEIVCN2i+VJsmnz6s86WzMSRw/5y6a0g==' \\\n" + " -H 'cache-control: no-cache' \\\n" + " -H 'content-type: application/json' \\\n" + " -H 'cookie: SPC_SI=3hs0YwAAAABjZENnSjgzZ5bfrQAAAAAAaHBRWEJ0QWQ=; SPC_F=hBrQhw0KNoxgTaQfmckmMB4htCvkC4Dh; REC_T_ID=76a50dcf-43ba-11ed-b7d1-2cea7fac4cc4; SPC_R_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_R_T_IV=R2JwaXZIQk5OemlSRm9pcA==; SPC_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_T_IV=R2JwaXZIQk5OemlSRm9pcA==; csrftoken=TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k; _gcl_au=1.1.543085384.1664870366; _med=refer; __LOCALE__null=ID' \\\n" + " -H 'pragma: no-cache' \\\n" + " -H 'referer: https://id.xiapibuy.com/Wardah-UV-Shield-Essential-Sunscreen-Gel-SPF-30-PA-40-ml-i.59763733.4656131375?sp_atk=b8bd5424-60fe-4e23-8c87-412b464083d1&xptdk=b8bd5424-60fe-4e23-8c87-412b464083d1' \\\n" + " -H 'sec-ch-ua: \"Google Chrome\";v=\"105\", \"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"105\"' \\\n" + " -H 'sec-ch-ua-mobile: ?0' \\\n" + " -H 'sec-ch-ua-platform: \"macOS\"' \\\n" + " -H 'sec-fetch-dest: empty' \\\n" + " -H 'sec-fetch-mode: cors' \\\n" + " -H 'sec-fetch-site: same-origin' \\\n" + " -H 'sz-token: false||MTAwMDI=' \\\n" + " -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' \\\n" + " -H 'x-api-source: pc' \\\n" + " -H 'x-csrftoken: TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k' \\\n" + " -H 'x-requested-with: XMLHttpRequest' \\\n" + " -H 'x-shopee-language: id' \\\n" + " -H 'x-sz-sdk-version: 2.3.2-4' \\\n" + " --compressed"; private static String postmanCurl = "curl --location --request GET 'https://id.xiapibuy.com/api/v4/item/get?itemid=4656131375&shopid=59763733' \\\n" + "--header 'authority: id.xiapibuy.com' \\\n" + "--header 'accept: application/json' \\\n" + "--header 'accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' \\\n" + "--header 'af-ac-enc-dat: AAcyLjMuMi00AAABg6IB9VoAAAxPAlcAAAAAAAAAALUc1tfPtx2eNZ+lQGEPXp3+N/SdzqNmxlp1L4tff1r27p8SwpcqlWoElPRl6ekEWeJsUptHCecgZgZUJNkMdyN9VJJ4Fcmn7nW9/iudAovi3Q4KeZFjs4yw8pGWNnYQjtmnppZkfx9s4w5mdq+xn6n9CtBqjYL9eKtscmx0v9UESe7UD5Fjs4yw8pGWNnYQjtmnppaeKwVmxFcF4ObDBrVINAKBdpYoBoaFxN4DV/pDl++L3/+NBeKB3wKlJvciBdWBBvaaeijPYf2G85HzJCJhO1xsKL1Rr43EU9rxBiNpNsgWiwTNue0ItFTg/V6S7yZ8b+URul/bNcp2Sur50wYMwSDikzRUuI9VU/LDpdQRLTm64iSmZ5ThVbxHE3bdSJ9U0k5djSR7fl8kZiNFp11d12JqI4GTqcIATPt0rYY/lg4GZoZ/6ktmA7MUhEIUj6kljFqZodbQEboXldfnVQFaMWIRrUq2io6kjRkGnw5JC7ja0YFovT2tvG0p7cDHKgUGL93c/eepLj1lWtbHvNydwzvOa8ZStWbkuVsfU1NJsDNWgQw2vl6G5BYjnlVUlNQzjfl60IFyefQS4QYdAcZKZtV5I4GTqcIATPt0rYY/lg4GZj+Nb4u1WHdUbCpXPApg4mao52Taa8i2RDDJAlpz1hDHJ3sXY0pNMunSQQvtExUbtN8KGuKS7t75OG7HfrT1pgMwhI+YiNH/GP07SAnecP+UZMBWDhT2yZm1nTpH6VAmUXk2o2vAiFhae2cy1xcnWzIzd2M3mBXX19lEIVCN2i+VJsmnz6s86WzMSRw/5y6a0g==' \\\n" + "--header 'cache-control: no-cache' \\\n" + "--header 'content-type: application/json' \\\n" + "--header 'cookie: SPC_SI=3hs0YwAAAABjZENnSjgzZ5bfrQAAAAAAaHBRWEJ0QWQ=; SPC_F=hBrQhw0KNoxgTaQfmckmMB4htCvkC4Dh; REC_T_ID=76a50dcf-43ba-11ed-b7d1-2cea7fac4cc4; SPC_R_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_R_T_IV=R2JwaXZIQk5OemlSRm9pcA==; SPC_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_T_IV=R2JwaXZIQk5OemlSRm9pcA==; csrftoken=TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k; _gcl_au=1.1.543085384.1664870366; _med=refer; __LOCALE__null=ID; SPC_R_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_R_T_IV=R2JwaXZIQk5OemlSRm9pcA==; SPC_SI=3hs0YwAAAABjZENnSjgzZ5bfrQAAAAAAaHBRWEJ0QWQ=; SPC_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_T_IV=R2JwaXZIQk5OemlSRm9pcA==' \\\n" + "--header 'pragma: no-cache' \\\n" + "--header 'referer: https://id.xiapibuy.com/Wardah-UV-Shield-Essential-Sunscreen-Gel-SPF-30-PA-40-ml-i.59763733.4656131375?sp_atk=b8bd5424-60fe-4e23-8c87-412b464083d1&xptdk=b8bd5424-60fe-4e23-8c87-412b464083d1' \\\n" + "--header 'sec-ch-ua: \"Google Chrome\";v=\"105\", \"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"105\"' \\\n" + "--header 'sec-ch-ua-mobile: ?0' \\\n" + "--header 'sec-ch-ua-platform: \"macOS\"' \\\n" + "--header 'sec-fetch-dest: empty' \\\n" + "--header 'sec-fetch-mode: cors' \\\n" + "--header 'sec-fetch-site: same-origin' \\\n" + "--header 'sz-token: false||MTAwMDI=' \\\n" + "--header 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' \\\n" + "--header 'x-api-source: pc' \\\n" + "--header 'x-csrftoken: TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k' \\\n" + "--header 'x-requested-with: XMLHttpRequest' \\\n" + "--header 'x-shopee-language: id' \\\n" + "--header 'x-sz-sdk-version: 2.3.2-4'"; private static String charlesUrl = "curl -H \"Host: id.xiapibuy.com\" -H \"Cookie: __LOCALE__null=ID; SPC_R_T_ID=ALV16yYYrJ954Cnd/qwq4ci/BJ9pEqXfZiOmxynSt3Fo/sBMtsXLmlfIV4vsCMvSB3suRczaBlCwhX00guo3dchuKO97Sjtk9V3yqqDwhv3Dtd8e6iLj2pjfYSi2aPImipqa47kYl7y/OO8pWfPg3j4ae9hGX5Q5pehCLg+Y2JU=; SPC_R_T_IV=RDB0YWZuaDdoYzlUQjl4TQ==; SPC_T_ID=ALV16yYYrJ954Cnd/qwq4ci/BJ9pEqXfZiOmxynSt3Fo/sBMtsXLmlfIV4vsCMvSB3suRczaBlCwhX00guo3dchuKO97Sjtk9V3yqqDwhv3Dtd8e6iLj2pjfYSi2aPImipqa47kYl7y/OO8pWfPg3j4ae9hGX5Q5pehCLg+Y2JU=; SPC_T_IV=RDB0YWZuaDdoYzlUQjl4TQ==; SPC_SI=5ho0YwAAAABwYTcwNFVsamdtsAAAAAAAeUVRUUE0VjA=; SPC_F=jCpKTv12KM6sXu0MdxxNCPdZ1f0NVTPC; REC_T_ID=db8d158c-43c7-11ed-a908-9440c93f746c; _gcl_au=1.1.2039763134.1664876118; csrftoken=TVdf0bEKtUAwodW82Xrs1lMkocbjUjMR; _QPWSDCXHZQA=a9e781f2-3192-47b2-df32-66b9f8b03504\" -H \"sec-ch-ua: \\\"Chromium\\\";v=\\\"104\\\", \\\" Not A;Brand\\\";v=\\\"99\\\", \\\"Yandex\\\";v=\\\"22\\\"\" -H \"sec-ch-ua-mobile: ?0\" -H \"x-sz-sdk-version: 2.3.2-4\" -H \"content-type: application/json\" -H \"accept: application/json\" -H \"x-shopee-language: id\" -H \"x-requested-with: XMLHttpRequest\" -H \"af-ac-enc-dat: AAcyLjMuMi00AAABg6KA2rMAAAxxAl0AAAAAAAAAALUc1tfqbJnquBjued3SPfDPNjZcwE5Y9CZDRAouDOTxYI6c0JcqlWoElPRl6ekEWeJsUptHCecgZgZUJNkMdyN9VJJ4Fcmn7nW9/iudAovi3Q4KeZFjs4yw8pGWNnYQjtmnppZkfx9s4w5mdq+xn6n9CtBqjYL9eKtscmx0v9UESe7UD5Fjs4yw8pGWNnYQjtmnppaeKwVmxFcF4ObDBrVINAKBq33VS+JVwnZ0HZWVGjz0oP+NBeKB3wKlJvciBdWBBvaaeijPYf2G85HzJCJhO1xsu7KKtg+IfFmuwykkfhJDjR2bU6BiP4jbbVh1cX3MKN0734doRzrCsZdk/6poJelfmVG2rUT03+NpNuFFxwWbIq+H8FsUC1SsOYA7uQssm6UlVhQnezi7GN9B49To0imbwzU6ZAIWKr3Tsiwkxq+NZB8hRld2WqENNTV9bukfQJwRul/bNcp2Sur50wYMwSDikzRUuI9VU/LDpdQRLTm64vGVFtzkzh3gjuLxgwquIESRZr8EptQTXXHI8QHpIBMd8cK6D+mS+izuW4fUEsbihmJFJkfOAnBywenZjD51w1BpGoHGvTBYivEZkbKzdr3CwzU6ZAIWKr3Tsiwkxq+NZBYm5PkcTch/SjQhPcsffZqfgIsuafgATPq8Uo4cqq7ZYeSCB+mwNST62/azLCJvzRryBkGqp2S6ViIMDM/xlofpdRoO+1stSFfsgxQ/QhMqhkWt0Sybvjx5xWkhiT5NjZY0NKdgbIimpnHd5HDrpP3ISU9CGiXXdY2/Gg2klBRMPyZ1BaM9cKQ3ySAPn6+ZjA==\" -H \"x-api-source: pc\" -H \"user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.114 YaBrowser/22.9.1.1081 Yowser/2.5 Safari/537.36\" -H \"x-csrftoken: TVdf0bEKtUAwodW82Xrs1lMkocbjUjMR\" -H \"sec-ch-ua-platform: \\\"macOS\\\"\" -H \"sec-fetch-site: same-origin\" -H \"sec-fetch-mode: cors\" -H \"sec-fetch-dest: empty\" -H \"referer: https://id.xiapibuy.com/Wardah-UV-Shield-Essential-Sunscreen-Gel-SPF-30-PA-40-ml-i.59763733.4656131375?sp_atk=b8bd5424-60fe-4e23-8c87-412b464083d1&xptdk=b8bd5424-60fe-4e23-8c87-412b464083d1\" -H \"accept-language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6\" --compressed \"https://id.xiapibuy.com/api/v4/item/get?itemid=4656131375&shopid=59763733\"";
^^ 666 而我仅仅是做了一些按 空格分割,然后传入 opt 🫢 如果有充分的测试,建议向仓库提一个 PR,然后请 @rockswang 合并一下~
private static String postmanCurl = "curl --location --request GET 'https://id.xiapibuy.com/api/v4/item/get?itemid=4656131375&shopid=59763733' \\\n" + "--header 'authority: id.xiapibuy.com' \\\n" + "--header 'accept: application/json' \\\n" + "--header 'accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7' \\\n" + "--header 'af-ac-enc-dat: AAcyLjMuMi00AAABg6IB9VoAAAxPAlcAAAAAAAAAALUc1tfPtx2eNZ+lQGEPXp3+N/SdzqNmxlp1L4tff1r27p8SwpcqlWoElPRl6ekEWeJsUptHCecgZgZUJNkMdyN9VJJ4Fcmn7nW9/iudAovi3Q4KeZFjs4yw8pGWNnYQjtmnppZkfx9s4w5mdq+xn6n9CtBqjYL9eKtscmx0v9UESe7UD5Fjs4yw8pGWNnYQjtmnppaeKwVmxFcF4ObDBrVINAKBdpYoBoaFxN4DV/pDl++L3/+NBeKB3wKlJvciBdWBBvaaeijPYf2G85HzJCJhO1xsKL1Rr43EU9rxBiNpNsgWiwTNue0ItFTg/V6S7yZ8b+URul/bNcp2Sur50wYMwSDikzRUuI9VU/LDpdQRLTm64iSmZ5ThVbxHE3bdSJ9U0k5djSR7fl8kZiNFp11d12JqI4GTqcIATPt0rYY/lg4GZoZ/6ktmA7MUhEIUj6kljFqZodbQEboXldfnVQFaMWIRrUq2io6kjRkGnw5JC7ja0YFovT2tvG0p7cDHKgUGL93c/eepLj1lWtbHvNydwzvOa8ZStWbkuVsfU1NJsDNWgQw2vl6G5BYjnlVUlNQzjfl60IFyefQS4QYdAcZKZtV5I4GTqcIATPt0rYY/lg4GZj+Nb4u1WHdUbCpXPApg4mao52Taa8i2RDDJAlpz1hDHJ3sXY0pNMunSQQvtExUbtN8KGuKS7t75OG7HfrT1pgMwhI+YiNH/GP07SAnecP+UZMBWDhT2yZm1nTpH6VAmUXk2o2vAiFhae2cy1xcnWzIzd2M3mBXX19lEIVCN2i+VJsmnz6s86WzMSRw/5y6a0g==' \\\n" + "--header 'cache-control: no-cache' \\\n" + "--header 'content-type: application/json' \\\n" + "--header 'cookie: SPC_SI=3hs0YwAAAABjZENnSjgzZ5bfrQAAAAAAaHBRWEJ0QWQ=; SPC_F=hBrQhw0KNoxgTaQfmckmMB4htCvkC4Dh; REC_T_ID=76a50dcf-43ba-11ed-b7d1-2cea7fac4cc4; SPC_R_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_R_T_IV=R2JwaXZIQk5OemlSRm9pcA==; SPC_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_T_IV=R2JwaXZIQk5OemlSRm9pcA==; csrftoken=TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k; _gcl_au=1.1.543085384.1664870366; _med=refer; __LOCALE__null=ID; SPC_R_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_R_T_IV=R2JwaXZIQk5OemlSRm9pcA==; SPC_SI=3hs0YwAAAABjZENnSjgzZ5bfrQAAAAAAaHBRWEJ0QWQ=; SPC_T_ID=/7xldhXHanp7KBghEVJaVfZNOWvxE6a7hGDnZ8M5m6k0/yXnnIcviXNEezwCMbGxwN42Sb070I6W8TQ7e5g1mRrie1RJYZFZs0Zdo3dPgrCtMOTN/KRYAXtIh/6cn+7S6b18kfT8dumaS0NIo/VdQ4uRS6KlVPNwxhSI754fQyA=; SPC_T_IV=R2JwaXZIQk5OemlSRm9pcA==' \\\n" + "--header 'pragma: no-cache' \\\n" + "--header 'referer: https://id.xiapibuy.com/Wardah-UV-Shield-Essential-Sunscreen-Gel-SPF-30-PA-40-ml-i.59763733.4656131375?sp_atk=b8bd5424-60fe-4e23-8c87-412b464083d1&xptdk=b8bd5424-60fe-4e23-8c87-412b464083d1' \\\n" + "--header 'sec-ch-ua: \"Google Chrome\";v=\"105\", \"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"105\"' \\\n" + "--header 'sec-ch-ua-mobile: ?0' \\\n" + "--header 'sec-ch-ua-platform: \"macOS\"' \\\n" + "--header 'sec-fetch-dest: empty' \\\n" + "--header 'sec-fetch-mode: cors' \\\n" + "--header 'sec-fetch-site: same-origin' \\\n" + "--header 'sz-token: false||MTAwMDI=' \\\n" + "--header 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' \\\n" + "--header 'x-api-source: pc' \\\n" + "--header 'x-csrftoken: TJGpFeZ9UnzPHqi40XFrP6mR6GflBl9k' \\\n" + "--header 'x-requested-with: XMLHttpRequest' \\\n" + "--header 'x-shopee-language: id' \\\n" + "--header 'x-sz-sdk-version: 2.3.2-4'"; private static String charlesUrl = "curl -H \"Host: id.xiapibuy.com\" -H \"Cookie: __LOCALE__null=ID; SPC_R_T_ID=ALV16yYYrJ954Cnd/qwq4ci/BJ9pEqXfZiOmxynSt3Fo/sBMtsXLmlfIV4vsCMvSB3suRczaBlCwhX00guo3dchuKO97Sjtk9V3yqqDwhv3Dtd8e6iLj2pjfYSi2aPImipqa47kYl7y/OO8pWfPg3j4ae9hGX5Q5pehCLg+Y2JU=; SPC_R_T_IV=RDB0YWZuaDdoYzlUQjl4TQ==; SPC_T_ID=ALV16yYYrJ954Cnd/qwq4ci/BJ9pEqXfZiOmxynSt3Fo/sBMtsXLmlfIV4vsCMvSB3suRczaBlCwhX00guo3dchuKO97Sjtk9V3yqqDwhv3Dtd8e6iLj2pjfYSi2aPImipqa47kYl7y/OO8pWfPg3j4ae9hGX5Q5pehCLg+Y2JU=; SPC_T_IV=RDB0YWZuaDdoYzlUQjl4TQ==; SPC_SI=5ho0YwAAAABwYTcwNFVsamdtsAAAAAAAeUVRUUE0VjA=; SPC_F=jCpKTv12KM6sXu0MdxxNCPdZ1f0NVTPC; REC_T_ID=db8d158c-43c7-11ed-a908-9440c93f746c; _gcl_au=1.1.2039763134.1664876118; csrftoken=TVdf0bEKtUAwodW82Xrs1lMkocbjUjMR; _QPWSDCXHZQA=a9e781f2-3192-47b2-df32-66b9f8b03504\" -H \"sec-ch-ua: \\\"Chromium\\\";v=\\\"104\\\", \\\" Not A;Brand\\\";v=\\\"99\\\", \\\"Yandex\\\";v=\\\"22\\\"\" -H \"sec-ch-ua-mobile: ?0\" -H \"x-sz-sdk-version: 2.3.2-4\" -H \"content-type: application/json\" -H \"accept: application/json\" -H \"x-shopee-language: id\" -H \"x-requested-with: XMLHttpRequest\" -H \"af-ac-enc-dat: AAcyLjMuMi00AAABg6KA2rMAAAxxAl0AAAAAAAAAALUc1tfqbJnquBjued3SPfDPNjZcwE5Y9CZDRAouDOTxYI6c0JcqlWoElPRl6ekEWeJsUptHCecgZgZUJNkMdyN9VJJ4Fcmn7nW9/iudAovi3Q4KeZFjs4yw8pGWNnYQjtmnppZkfx9s4w5mdq+xn6n9CtBqjYL9eKtscmx0v9UESe7UD5Fjs4yw8pGWNnYQjtmnppaeKwVmxFcF4ObDBrVINAKBq33VS+JVwnZ0HZWVGjz0oP+NBeKB3wKlJvciBdWBBvaaeijPYf2G85HzJCJhO1xsu7KKtg+IfFmuwykkfhJDjR2bU6BiP4jbbVh1cX3MKN0734doRzrCsZdk/6poJelfmVG2rUT03+NpNuFFxwWbIq+H8FsUC1SsOYA7uQssm6UlVhQnezi7GN9B49To0imbwzU6ZAIWKr3Tsiwkxq+NZB8hRld2WqENNTV9bukfQJwRul/bNcp2Sur50wYMwSDikzRUuI9VU/LDpdQRLTm64vGVFtzkzh3gjuLxgwquIESRZr8EptQTXXHI8QHpIBMd8cK6D+mS+izuW4fUEsbihmJFJkfOAnBywenZjD51w1BpGoHGvTBYivEZkbKzdr3CwzU6ZAIWKr3Tsiwkxq+NZBYm5PkcTch/SjQhPcsffZqfgIsuafgATPq8Uo4cqq7ZYeSCB+mwNST62/azLCJvzRryBkGqp2S6ViIMDM/xlofpdRoO+1stSFfsgxQ/QhMqhkWt0Sybvjx5xWkhiT5NjZY0NKdgbIimpnHd5HDrpP3ISU9CGiXXdY2/Gg2klBRMPyZ1BaM9cKQ3ySAPn6+ZjA==\" -H \"x-api-source: pc\" -H \"user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.114 YaBrowser/22.9.1.1081 Yowser/2.5 Safari/537.36\" -H \"x-csrftoken: TVdf0bEKtUAwodW82Xrs1lMkocbjUjMR\" -H \"sec-ch-ua-platform: \\\"macOS\\\"\" -H \"sec-fetch-site: same-origin\" -H \"sec-fetch-mode: cors\" -H \"sec-fetch-dest: empty\" -H \"referer: https://id.xiapibuy.com/Wardah-UV-Shield-Essential-Sunscreen-Gel-SPF-30-PA-40-ml-i.59763733.4656131375?sp_atk=b8bd5424-60fe-4e23-8c87-412b464083d1&xptdk=b8bd5424-60fe-4e23-8c87-412b464083d1\" -H \"accept-language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6\" --compressed \"https://id.xiapibuy.com/api/v4/item/get?itemid=4656131375&shopid=59763733\"";
我会尝试添加测试并提交一个PR,但是我此代码在本库中该如何组织(更符合作者的对代码的设计意图)暂时没有很好的想法。如果 @rockswang 有兴趣对这些代码进行整合我会非常感谢。