使用libcurl进行Digest认证时收到两个响应,如何仅获取第二个?
解决libcurl Digest认证时回调多次响应的问题
针对你遇到的Digest认证导致回调收到两次响应(401+200)的问题,可以通过以下方式让libcurl仅保留最终200响应的状态码、响应头和内容:
核心思路
利用libcurl的CURLOPT_HEADERFUNCTION单独处理响应头,在回调中识别状态码,仅标记并保留成功响应(200系列)的头和体数据;同时配合CURLOPT_WRITEFUNCTION过滤无效响应的body内容。
具体实现步骤
1. 定义响应数据结构体
用来存储响应状态、状态码、头和体内容:
#include <string> #include <cstdio> #include <curl/curl.h> struct ResponseData { bool is_valid_response; // 标记当前是否为有效响应 long status_code; // 响应状态码 std::string header; // 响应头内容 std::string body; // 响应体内容 };
2. 实现响应头回调函数
在回调中解析状态行,判断响应是否有效,仅保存有效响应的头信息:
size_t header_callback(char* buffer, size_t size, size_t nitems, void* userdata) { ResponseData* resp = static_cast<ResponseData*>(userdata); const size_t total_size = size * nitems; // 匹配HTTP状态行(格式如:HTTP/1.1 200 OK) if (strncmp(buffer, "HTTP/", 5) == 0) { // 提取状态码 sscanf(buffer, "HTTP/%*d.%*d %ld", &resp->status_code); // 仅将200-299区间的状态码视为有效响应 resp->is_valid_response = (resp->status_code >= 200 && resp->status_code < 300); // 若为无效响应,清空之前积累的内容 if (!resp->is_valid_response) { resp->header.clear(); resp->body.clear(); } } // 仅当响应有效时,保存头内容 if (resp->is_valid_response) { resp->header.append(buffer, total_size); } return total_size; }
3. 实现响应体回调函数
仅处理有效响应的body数据:
size_t write_callback(char* buffer, size_t size, size_t nitems, void* userdata) { ResponseData* resp = static_cast<ResponseData*>(userdata); const size_t total_size = size * nitems; // 仅处理有效响应的body if (resp->is_valid_response) { resp->body.append(buffer, total_size); } // 无论是否处理,都返回接收的总大小,避免libcurl报错 return total_size; }
4. 配置并执行curl请求
设置认证方式、回调函数,执行请求后即可获取仅包含200响应的数据:
int main() { curl_global_init(CURL_GLOBAL_ALL); CURL* curl = curl_easy_init(); if (curl) { ResponseData resp{}; // 初始化结构体 // 设置请求URL curl_easy_setopt(curl, CURLOPT_URL, "http://你的IP摄像头地址"); // 启用Digest认证 curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); // 设置用户名密码 curl_easy_setopt(curl, CURLOPT_USERPWD, "用户名:密码"); // 绑定头回调函数及数据 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &resp); // 绑定体回调函数及数据 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp); // 执行请求 const CURLcode res = curl_easy_perform(curl); if (res == CURLE_OK) { // 输出有效响应的内容 printf("状态码: %ld\n", resp.status_code); printf("响应头:\n%s\n", resp.header.c_str()); printf("响应体:\n%s\n", resp.body.c_str()); } else { fprintf(stderr, "请求失败: %s\n", curl_easy_strerror(res)); } curl_easy_cleanup(curl); } curl_global_cleanup(); return 0; }
关键说明
- 无需设置
CURLOPT_HEADER,该选项会将头和体混合传入WRITEFUNCTION,而使用CURLOPT_HEADERFUNCTION可以更精准地处理头信息。 - libcurl 7.72完全支持上述所有选项,无需版本兼容问题。
- 该方案会自动忽略Digest认证过程中产生的401响应,仅保留最终成功的200响应数据。
内容的提问来源于stack exchange,提问作者bogdan
相关产品推荐
相关产品推荐

