You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在libcurl中复现特殊curl请求:部分参数大括号不编码

问题:libcurl复现特殊编码的curl请求

在命令行中,存在一个包含两个带大括号的查询参数的curl请求,其中一个参数必须URL编码才有效,另一个必须不编码:

有效请求示例(返回3个ID的数据)

curl -X GET "https://example.com/search?TIME=%7B%22TIME_TYPE%22%3A%22MESSAGE%22%2C%22MESSAGENUMBER%22%3A5%7D&P_ID={1,2,3}"
  • TIME参数的大括号已URL编码(%7B和%7D)
  • P_ID参数的大括号未编码

无效请求示例(忽略P_ID,返回所有用户数据)

  • curl -X GET "https://example.com/search?TIME=%7B%22TIME_TYPE%22%3A%22MESSAGE%22%2C%22MESSAGENUMBER%22%3A5%7D&P_ID=%7B1,2,3%7D"(P_ID大括号编码)
  • curl -X GET "https://example.com/search?TIME=%7B%22TIME_TYPE%22%3A%22MESSAGE%22%2C%22MESSAGENUMBER%22%3A5%7D&P_ID=1&P_ID=2&P_ID=3"(多P_ID参数)
  • curl -X GET "https://example.com/search?TIME={%22TIME_TYPE%22%3A%22MESSAGE%22%2C%22MESSAGENUMBER%22%3A5}&P_ID=1&P_ID=2&P_ID=3"(TIME大括号未编码)

尝试用libcurl的CURLUPART实现时出现错误,代码如下:

void *curlHandle;
curl_easy_reset(curlHandle);
CURLU *url = curl_url();
curl_url_set(url, CURLUPART_URL, "example.com", 0);
curl_url_set(url, CURLUPART_QUERY, "P_ID={1,2,3}", CURLU_APPENDQUERY);
curl_url_set(url, CURLUPART_QUERY, "TIME=%7B%22TIME_TYPE%22%3A%22MESSAGE%22%2C%22MESSAGENUMBER%22%3A5%7D", CURLU_APPENDQUERY);
curl_url_set(url, CURLUPART_SCHEME, "https", 0);
curl_url_set(url, CURLUPART_PATH, "/search/", 0);
curl_easy_setopt(curlHandle, CURLOPT_CURLU, url);
curl_easy_perform(curlHandle);

错误信息:

  • No URL set
    Curl failed with error 3: URL using bad/illegal format or missing URL. 0 retries remaining

解决方法

1. 修复CURLUPART代码错误

你的CURLUPART代码存在两个关键问题:

  • curlHandle未初始化,直接调用curl_easy_reset会导致未定义行为,需先通过curl_easy_init()创建句柄
  • URL设置顺序错误,应先指定scheme和主机,再配置其他部分

修正后的代码:

CURL *curlHandle = curl_easy_init(); // 初始化句柄
if(curlHandle) {
    CURLU *url = curl_url();
    // 先设置scheme和主机
    curl_url_set(url, CURLUPART_SCHEME, "https", 0);
    curl_url_set(url, CURLUPART_HOST, "example.com", 0);
    curl_url_set(url, CURLUPART_PATH, "/search", 0);
    // 添加查询参数,用CURLU_NON_SUPPORT_SCHEME避免自动编码
    curl_url_set(url, CURLUPART_QUERY, "TIME=%7B%22TIME_TYPE%22%3A%22MESSAGE%22%2C%22MESSAGENUMBER%22%3A5%7D", CURLU_APPENDQUERY | CURLU_NON_SUPPORT_SCHEME);
    curl_url_set(url, CURLUPART_QUERY, "P_ID={1,2,3}", CURLU_APPENDQUERY | CURLU_NON_SUPPORT_SCHEME);
    
    curl_easy_setopt(curlHandle, CURLOPT_CURLU, url);
    CURLcode res = curl_easy_perform(curlHandle);
    if(res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
    }
    // 清理资源
    curl_url_cleanup(url);
    curl_easy_cleanup(curlHandle);
}
  • CURLU_NON_SUPPORT_SCHEME选项会让libcurl不对查询参数做自动编码,保留你传入的原始格式(包括未编码的P_ID大括号和已编码的TIME参数)

2. 直接构造完整URL并禁用自动编码

如果CURLUPART方式仍有问题,可以直接拼接符合要求的完整URL字符串,通过CURLOPT_URL设置,同时确保不触发自动编码:

CURL *curlHandle = curl_easy_init();
if(curlHandle) {
    const char *fullUrl = "https://example.com/search?TIME=%7B%22TIME_TYPE%22%3A%22MESSAGE%22%2C%22MESSAGENUMBER%22%3A5%7D&P_ID={1,2,3}";
    curl_easy_setopt(curlHandle, CURLOPT_URL, fullUrl);
    // 禁用额外的内容编码转换,确保URL格式完全保留
    curl_easy_setopt(curlHandle, CURLOPT_ENCODING, "");
    
    CURLcode res = curl_easy_perform(curlHandle);
    if(res != CURLE_OK) {
        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
    }
    curl_easy_cleanup(curlHandle);
}

注意:直接拼接URL时要确保字符串完全符合有效格式,避免包含其他非法字符。


额外问题解答

除已尝试的4种方法,还有其他方式吗?

  • 可以用curl_easy_escape手动编码TIME参数,再拼接P_ID的原始字符串,构造完整URL后设置给libcurl,这种方式更灵活,能精准控制每个参数的编码状态。
  • 不推荐用CURLOPT_POSTFIELDS模拟GET请求(将查询参数放在POSTFIELDS中,设置CURLOPT_CUSTOMREQUEST为"GET"),这种方式不符合HTTP规范,可能引发兼容性问题。

是否应该联系API所有者?

非常建议联系API所有者询问这种特殊编码要求的原因:

  • 这种不一致的编码逻辑不符合URL标准(RFC 3986),大括号属于保留字符,理论上编码或不编码都应被正确解析,API的特殊处理大概率是实现bug或未公开的规则。
  • 了解原因后,你可以确认是否存在更规范的调用方式,避免后续API更新导致当前的特殊调用方式失效。

内容的提问来源于stack exchange,提问作者rabbitdude

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 19:20:30