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

对接Royal Mail API V4:libcurl实现curl --data-urlencode功能遇错求助

问题

尝试用C语言结合libcurl对接Royal Mail API V4获取令牌,已有可用的curl命令行脚本能通过--data-urlencode成功获取令牌:

curl -k --location 'https://authentication.proshipping.net/connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=AAAAAAA' \
--data-urlencode 'client_secret=BBBBBBBBB' \
--data-urlencode 'grant_type=client_credentials'

但自行编写的libcurl代码返回{"error":"invalid_client"},代码如下:

curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_easy_setopt(hnd, CURLOPT_URL, "https://authentication.proshipping.net/connect/token");
curl_easy_setopt(hnd, CURLOPT_POST, TRUE);

headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

postfields = curl_slist_append(postfields, "client_id=AAAAAAA");
postfields = curl_slist_append(postfields, "client_secret=BBBBBBBBB");
postfields = curl_slist_append(postfields, "grant_type=client_credentials");
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, postfields);

curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &s);

res = curl_easy_perform(hnd);

请问如何在libcurl中实现curl --data-urlencode的等价功能?

解决方案

你的核心错误是误用了curl_slist链表给CURLOPT_POSTFIELDS赋值:CURLOPT_POSTFIELDS需要的是一个URL编码后的字符串(对应application/x-www-form-urlencoded格式),而curl_slist是用于构造multipart/form-data类型表单(对应CURLOPT_HTTPPOST选项)的。服务器收到错误格式的请求,因此返回invalid_client。

要实现--data-urlencode的等价功能,需按以下步骤操作:

  1. 对每个参数值进行URL编码:
    使用curl_easy_escape函数对参数值进行URL编码,这对应--data-urlencode的编码逻辑,确保特殊字符(如&、=、空格等)被正确转义。

  2. 拼接成标准的URL编码字符串:
    将编码后的参数按key=encoded_value&key2=encoded_value2的格式拼接成完整的POST数据字符串。

  3. 正确设置CURLOPT_POSTFIELDS:
    将拼接好的字符串传给CURLOPT_POSTFIELDS,而非链表。

修正后的代码片段

替换你原代码中构造postfields链表及设置CURLOPT_POSTFIELDS的部分:

curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_easy_setopt(hnd, CURLOPT_URL, "https://authentication.proshipping.net/connect/token");
curl_easy_setopt(hnd, CURLOPT_POST, TRUE);

// 设置Content-Type头(也可省略,libcurl会自动为urlencoded数据添加该头)
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

// 对每个参数值进行URL编码
char *encoded_client_id = curl_easy_escape(hnd, "AAAAAAA", 0);
char *encoded_client_secret = curl_easy_escape(hnd, "BBBBBBBBB", 0);
char *encoded_grant_type = curl_easy_escape(hnd, "client_credentials", 0);

// 拼接POST数据
char post_data[256];
snprintf(post_data, sizeof(post_data), 
         "client_id=%s&client_secret=%s&grant_type=%s",
         encoded_client_id, encoded_client_secret, encoded_grant_type);

// 释放编码后的内存(必须调用curl_free,不能用free)
curl_free(encoded_client_id);
curl_free(encoded_client_secret);
curl_free(encoded_grant_type);

// 设置POST数据
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, post_data);

curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &s);

res = curl_easy_perform(hnd);

关键说明

  • curl_easy_escape会自动处理参数值中的特殊字符,完全等价于--data-urlencode的编码行为。
  • 编码后的内存必须用curl_free释放,不能用标准C的free,避免内存泄漏或错误。
  • 如果参数值长度不确定,建议使用动态内存分配(如asprintf)来拼接POST数据,避免栈溢出风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:35:01