当前位置:首页 > 综合

c调用post接口案例

libcurl是口案C语言里最常用的HTTP客户端库。一个POST请求,口案代码量不大,口案但坑不少。口案直接看一个能跑的口案案例——向JSON接口提交用户数据。

#include <stdio.h> #include <string.h> #include <curl/curl.h> static size_t write_cb(char *ptr,口案 size_t size, size_t nmemb, void *userdata) {  size_t total = size * nmemb; fwrite(ptr, 1, total, (FILE*)userdata); return total; } int main(void) {  CURL *curl = curl_easy_init(); if (!curl) return -1; struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: application/json"); headers = curl_slist_append(headers, "Accept: application/json"); const char *json_data = "{ \"name\":\"张三\",\"age\":30}"; curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.100:8080/api/user"); curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); FILE *resp = fopen("resp.txt", "w"); if (!resp) {  curl_slist_free_all(headers); curl_easy_cleanup(curl); return -1; } curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) fprintf(stderr, "请求失败: %s\n", curl_easy_strerror(res)); else printf("HTTP状态码: %ld\n", curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res); // 注意这行有误,见下文 fclose(resp); curl_slist_free_all(headers); curl_easy_cleanup(curl); return 0; }

上面代码里有个故意的口案错误——curl_easy_getinfo的用法写错了。正确的口案做法是先声明一个long http_code变量,再传它的口案地址。修正后的口案代码逻辑是这样的:

long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); printf("HTTP状态码: %ld\n", http_code);

写这个案例时我踩过几个实际的坑。第一,口案POSTFIELDS必须指向有效内存,口案curl不会帮你拷贝字符串——如果json_data是口案局部变量,在curl_easy_perform之前不能释放。口案第二,口案响应回调如果不设置,curl会把响应体直接打印到stdout,这在调试时干扰视线。第三,Content-Type头不带charset,服务端解析UTF-8没问题,但遇到GBK编码的字符串就得显式转换。

还有一点容易被忽略:curl默认的POST行为是application/x-www-form-urlencoded。如果你忘了设置自定义头,服务端拿到的不是JSON,而是类似name=%E5%BC%A0%E4%B8%89&age=30这种表单串。我见过不少新手在这栽跟头,返回400还一头雾水。

实际项目中,响应数据往往不是写文件,而是存内存。这时回调函数要自己管理缓冲区。比如动态增长的内存块——每次回调时realloc,然后memcpy。注意处理多次回调的情况,因为TCP分片可能导致一个HTTP响应被拆成几段到达。

调试技巧也有用。curl_easy_setopt设置CURLOPT_VERBOSE, 1L,就能在stderr看到完整的请求头和响应头。如果接口返回异常,先看这个输出,比瞎猜快得多。另外,CURLOPT_SSL_VERIFYPEER和CURLOPT_SSL_VERIFYHOST在测试自签名HTTPS时得设为0,但生产环境千万别这么干。

回到性能。一次POST的耗时通常在毫秒级,但如果你在循环里调用,每次都要重新curl_easy_init/cleanup,开销不小。更好的做法是复用CURL句柄,用curl_easy_reset清理状态,再重新设置URL和POSTFIELDS。我做过一个批量上报的模块,从每次新建句柄改成复用后,吞吐量提升了近40%。

最后提醒一句:POSTFIELDS里的JSON字符串,如果包含转义引号或换行,直接用字符串拼接容易出错。建议用snprintf拼好,或者干脆用json-c这类库生成。别小看这个,线上出过因为少写一个反斜杠导致整个请求失败的案例。

分享到: