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

如何使用libcurl编写HTTP GET请求封装函数并获取响应头和响应体

修正方案与代码实现

原有代码的核心问题

  • 选项用错:CURLOPT_WRITEHEADER 是用来给头回调传递自定义userdata指针的,设置头回调函数应该用 CURLOPT_HEADERFUNCTION,之前把回调函数错传给了CURLOPT_WRITEHEADER,逻辑完全错位
  • 回调参数理解错误:所有libcurl的写入回调参数含义统一:
    • buffer:libcurl收到的临时数据块,回调结束后会被回收,不能直接赋值保存指针,必须拷贝内容
    • size * nitems:本次收到的数据块总字节长度
    • userdata:就是提前通过对应选项传入的自定义指针,这里就是你的http_response_t结构体指针
  • 回调返回值错误:必须返回实际处理的字节数(一般就是size * nitems),如果返回值小于这个数,libcurl会直接终止请求,绝对不能返回结构体指针
  • 缺少动态内存处理:响应体和响应头都是分段接收的,需要动态扩容存储,不能直接赋值临时buffer
  • 缺少状态码获取逻辑:需要调用curl_easy_getinfo获取HTTP状态码填充结构体

修正后的完整代码

首先调整结构体定义,增加头计数和响应体长度字段:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>

#define MAX_HEADERS 100

typedef struct {
  char* key;
  char* value;
} http_header_t;

typedef struct {
  int status;
  char *body;
  size_t body_len;
  http_header_t headers[MAX_HEADERS];
  int header_count;
} http_response_t;

补全响应体写入回调:

size_t http_response_write(void *ptr, size_t size, size_t nmemb, void* userdata) {
  size_t real_size = size * nmemb;
  http_response_t *resp = (http_response_t*)userdata;

  // 动态扩容响应体内存
  char *new_body = realloc(resp->body, resp->body_len + real_size + 1);
  if (!new_body) return 0; // 内存分配失败终止请求

  resp->body = new_body;
  memcpy(resp->body + resp->body_len, ptr, real_size);
  resp->body_len += real_size;
  resp->body[resp->body_len] = '\0'; // 字符串结尾补0方便使用

  return real_size;
}

补全响应头写入回调:

size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) {
  size_t real_size = size * nitems;
  http_response_t *resp = (http_response_t*)userdata;

  // 过滤空行(头结束的标记)
  if (real_size <= 2 || resp->header_count >= MAX_HEADERS) return real_size;

  // 拆分key和value,头的格式是 Key: Value\r\n
  char *colon = strchr(buffer, ':');
  if (!colon) return real_size;

  // 拷贝key
  int key_len = colon - buffer;
  resp->headers[resp->header_count].key = malloc(key_len + 1);
  strncpy(resp->headers[resp->header_count].key, buffer, key_len);
  resp->headers[resp->header_count].key[key_len] = '\0';

  // 跳过冒号和前面的空格拷贝value
  char *val_start = colon + 1;
  while (*val_start == ' ' || *val_start == '\t') val_start++;
  char *val_end = buffer + real_size - 2; // 去掉末尾的\r\n
  int val_len = val_end - val_start + 1;
  resp->headers[resp->header_count].value = malloc(val_len + 1);
  strncpy(resp->headers[resp->header_count].value, val_start, val_len);
  resp->headers[resp->header_count].value[val_len] = '\0';

  resp->header_count++;
  return real_size;
}

修正后的http_get函数:

void http_get(http_response_t *response, const char *url) {
  // 先初始化传入的response结构体,避免野指针
  memset(response, 0, sizeof(http_response_t));

  CURL *curl = curl_easy_init();
  if (curl) {
    curl_easy_setopt(curl, CURLOPT_URL, url);
    // 正确设置头回调和对应的userdata
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, response);
    // 设置响应体回调和对应的userdata
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_response_write);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    
    CURLcode res = curl_easy_perform(curl);
    if (res == CURLE_OK) {
      // 获取HTTP状态码
      long status_code;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);
      response->status = (int)status_code;
    }

    curl_easy_cleanup(curl);
  }
}

使用注意事项

  • 调用http_get前不需要手动初始化http_response_t,函数内部已经做了memset清零
  • 使用完响应结果后必须手动释放内存,避免泄漏:
    void free_http_response(http_response_t *resp) {
      if (resp->body) free(resp->body);
      for (int i = 0; i < resp->header_count; i++) {
        free(resp->headers[i].key);
        free(resp->headers[i].value);
      }
      memset(resp, 0, sizeof(http_response_t));
    }
    

内容的提问来源于stack exchange,提问作者The epic face 007

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 11:27:04