封裝一個通用的 `http_post` 函數,支持自定義 URL、表單數據、寫入回調、錯誤處理、Cookie 持久化。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
// 回調函數:將響應數據寫入 FILE*
static size_t write_callback(void* buffer, size_t size, size_t nmemb, void* userp) {
FILE* fp = (FILE*)userp;
return fwrite(buffer, size, nmemb, fp);
}
// 通用 POST 函數
// 返回 0 成功,非 0 失敗 (錯誤碼見 CURLE_*)
int http_post(const char* url, const char* post_fields, const char* response_file, const char* cookie_file) {
CURL* curl = curl_easy_init();
if (!curl) { fprintf(stderr, "curl_easy_init failed\n"); return -1; }
FILE* fp = fopen(response_file, "wb");
if (!fp) { fprintf(stderr, "fopen %s failed\n", response_file); curl_easy_cleanup(curl); return -2; }
// 設置選項
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // 支持 3xx 重定向
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_file); // 讀取 Cookie
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_file); // 保存 Cookie (登錄態保持)
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // 調試輸出
curl_easy_setopt(curl, CURLOPT_HEADER, 1L); // 將響應頭也寫入文件
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); // 超時 30s
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); // 連接超時 10s
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 忽略證書驗證 (測試用,生產應配置 CA)
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
// 執行請求
CURLcode res = curl_easy_perform(curl);
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
fclose(fp);
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform failed: %s\n", curl_easy_strerror(res));
return res;
}
if (http_code != 200) {
fprintf(stderr, "HTTP error: %ld\n", http_code);
return -3;
}
return 0;
}
// 日誌文件追記讀取並逐行 POST (模擬需求偽代碼)
void process_log_queue(const char* url, const char* log_file) {
FILE* fp = fopen(log_file, "r+");
if (!fp) return;
char line[4096];
long pos = 0;
while (fgets(line, sizeof(line), fp)) {
// 去除換行
line[strcspn(line, "\r\n")] = 0;
if (strlen(line) == 0) continue;
char response_file[256];
sprintf(response_file, "resp_%ld.tmp", time(NULL));
int ret = http_post(url, line, response_file, "cookies.txt");
if (ret == 0) {
// 成功:從日誌文件中刪除該行 (簡易實現:重寫文件,實際建議用 SQLite 或單獨隊列文件)
printf("POST success: %s\n", line);
} else {
printf("POST failed, keep in log: %s\n", line);
}
}
fclose(fp);
}
int main() {
curl_global_init(CURL_GLOBAL_ALL);
// 示例 1: 直接 POST 登錄
const char* login_url = "https://www.example.com/login";
const char* login_data = "username=test&password=123456&remember=1";
http_post(login_url, login_data, "login_resp.html", "cookies.txt");
// 示例 2: 處理日誌隊列
// process_log_queue("https://api.example.com/log", "log.txt");
curl_global_cleanup();
return 0;
}
gcc -o curl_post curl_post.c -lcurl
# 或 MSVC
cl curl_post.c libcurl.lib