java-curl icon indicating copy to clipboard operation
java-curl copied to clipboard

可以实现对 cURL 解析吗?

Open ReberMusk opened this issue 2 years ago • 6 comments

ReberMusk avatar Apr 18 '22 04:04 ReberMusk

解析是什么意思,我这个就是可以在java程序里用字符串格式的curl命令来发起各种http请求

rockswang avatar Apr 22 '22 08:04 rockswang

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);

ReberMusk avatar Apr 22 '22 09:04 ReberMusk

可以的,兼容大部分常用命令和开关

rockswang avatar Apr 22 '22 09:04 rockswang

拉下来尝试了一下,好像没有解析的 API ~ 我核心诉求是自己懒得解析输入的 cURL 了。 可能需要一个 CUrl cUrl = CurlHelper.parse("curl --location --request GET '127.0.0.1/manage/xx/xxx'"); 🥲

ReberMusk avatar Apr 22 '22 11:04 ReberMusk

把所有参数分割按空格分割然后用opt依次传入即可: new CUrl().opt('127.0.0.1/manage/xx/xxx', '--location', '--request', 'GET') .exec(null)

rockswang avatar Apr 25 '22 00:04 rockswang

比方说解析出各种参数返回一个map

kings1990 avatar Jun 14 '22 07:06 kings1990

我有同样的需要,所以我写了一个工具类。用来将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\"";

theten52 avatar Oct 07 '22 17:10 theten52

不错不错!

rockswang avatar Oct 08 '22 01:10 rockswang

我有同样的需要,所以我写了一个工具类。用来将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 合并一下~

ReberMusk avatar Oct 08 '22 16:10 ReberMusk

    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 有兴趣对这些代码进行整合我会非常感谢。

theten52 avatar Oct 10 '22 18:10 theten52