libcurl 条件请求判定:CURLINFO_CONDITION_UNMET 使用指南
2026/9/10 14:20:05 网站建设 项目流程

libcurl 条件请求判定:CURLINFO_CONDITION_UNMET 使用指南

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

本篇技术指南围绕 libcurl 提供的CURLINFO_CONDITION_UNMET信息选项展开,讲解如何通过curl_easy_getinfo判断一次基于时间条件的 HTTP/FTP/FILE 传输是否因条件未满足而被跳过(例如服务器返回 304 或资源未按预期更新),并结合当前仓库源码剖析其底层实现与判定逻辑。读完本文,你将掌握条件请求的完整搭配方案、返回值语义与实战代码写法。

什么是 CURLINFO_CONDITION_UNMET

CURLINFO_CONDITION_UNMET是 libcurl 的一个信息(info)选项,用于在传输结束后查询:上一次请求设置的时间条件(time condition)是否未被满足。它属于long类型的 getinfo 选项(枚举值为CURLINFO_LONG + 35,定义见 include/curl/curl.h),自 curl 7.19.4 版本起加入,仅适用于 HTTP 协议。

典型场景:当客户端发送带If-Modified-Since之类的条件请求,服务器判定资源未更新,于是不返回文档正文。此时curl_easy_perform仍然返回CURLE_OK(毕竟请求本身成功了),但下载到的数据量为零。如果不对返回内容加以区分,很容易把"资源未更新"误当成"下载失败"或"空文件"。CURLINFO_CONDITION_UNMET正是用来消解这种歧义的:它告诉你这次成功的空传输到底是"条件未满足"还是"本来就该这样"。

接口原型

#include <curl/curl.h> CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONDITION_UNMET, long *unmet);

传入一个指向long的指针,curl_easy_getinfo会把结果写入该变量:

  • 返回1:之前请求中设置的条件未匹配。即你没有拿到数据,是因为资源不满足你提出的时间条件;
  • 返回0:条件已满足(或从未设置条件),传输正常进行。

此外,即使你没有显式设置时间条件,只要服务器以HTTP 304状态码响应(例如客户端主动发送了自定义的If-Match-*请求头),该选项同样会返回 1。

底层实现:flag 如何被置位

getinfo 的读取逻辑

curl_easy_getinfoCURLINFO_CONDITION_UNMET的处理位于 lib/getinfo.c:

case CURLINFO_CONDITION_UNMET: if(data->info.httpcode == 304) *param_longp = 1L; else /* return if the condition prevented the document to get transferred */ *param_longp =>bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) { if((timeofdoc == 0) || (data->set.timevalue == 0)) return TRUE; switch(data->set.timecondition) { case CURL_TIMECOND_IFMODSINCE: default: if(timeofdoc <=>int main(void) { CURL *curl = curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); /* January 1, 2020 is 1577833200 */ curl_easy_setopt(curl, CURLOPT_TIMEVALUE, 1577833200L); /* If-Modified-Since the above time stamp */ curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); /* Perform the request */ result = curl_easy_perform(curl); if(result == CURLE_OK) { /* check the time condition */ long unmet; result = curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &unmet); if(result == CURLE_OK) { printf("The time condition was %sfulfilled\n", unmet ? "NOT" : ""); } } curl_easy_cleanup(curl); } return 0; }

代码要点:

  1. CURLOPT_TIMEVALUE设置对比用的时间戳(Unix 秒数),示例中1577833200即 2020-01-01 00:00:00 UTC;
  2. CURLOPT_TIMECONDITION设置为CURL_TIMECOND_IFMODSINCE,表示"只在资源修改时间晚于该时间戳时才传输";
  3. curl_easy_perform返回CURLE_OK后,用CURLINFO_CONDITION_UNMET查询条件是否未满足;
  4. unmet为 1 时打印NOT fulfilled,说明传输被条件跳过;为 0 时打印fulfilled,说明资源满足条件、数据已正常接收。

配套选项与时间条件语义

CURLINFO_CONDITION_UNMET本身只负责"查询结果",条件请求的建立依赖两个 setopt 选项(详见 docs/libcurl/opts/CURLOPT_TIMECONDITION.md):

选项作用取值
CURLOPT_TIMEVALUE指定对比用时间戳(Unix 时间,秒)long 类型
CURLOPT_TIMECONDITION定义时间值的处理方式CURL_TIMECOND_IFMODSINCE/CURL_TIMECOND_IFUNMODSINCE(默认CURL_TIMECOND_NONE,即 0)

相关枚举定义见 include/curl/curl.h:

#define CURL_TIMECOND_NONE 0L #define CURL_TIMECOND_IFMODSINCE 1L #define CURL_TIMECOND_IFUNMODSINCE 2L #define CURL_TIMECOND_LASTMOD 3L

HTTP 请求头由 lib/http.c 根据条件类型生成:

  • CURL_TIMECOND_IFMODSINCE→ 发送If-Modified-Since头;
  • CURL_TIMECOND_IFUNMODSINCE→ 发送If-Unmodified-Since头;
  • CURL_TIMECOND_LASTMOD→ 发送Last-Modified头(仅影响响应处理)。

若代码中已通过CURLOPT_HTTPHEADER显式设置了同名自定义头,libcurl 会优先使用自定义头、不再重复生成(见 lib/http.c)。HTTP 时间头按 RFC 2616 要求使用 GMT 格式输出。

与命令行工具的对应关系

curl 命令行工具通过-z, --time-cond暴露同一能力(见 docs/cmdline-opts/time-cond.md):

# 请求在指定时间之后修改过的资源 curl -z "Wed 01 Sep 2021 12:18:00" https://example.com/ # 从文件读取时间戳 curl -z file $URL

--time-condCURLOPT_TIMECONDITION+CURLOPT_TIMEVALUE一一对应,CURLINFO_CONDITION_UNMET则对应命令行模式下curl -z时的内部判定结果。若需在命令行场景获得等价信息,可结合-w "%{http_code}"观察 304 状态码。

返回值与错误处理

  • curl_easy_getinfo返回CURLE_OK (0)表示查询成功;
  • 返回非零值表示出错,具体错误码见 docs/libcurl/opts/libcurl-errors.md(如传入非法句柄或选项类型不匹配等)。

需要强调的是:该选项是查询型接口,必须在curl_easy_perform完成之后调用;在传输过程中调用拿到的可能是旧值。另外,CURLINFO_CONDITION_UNMETlong类型选项,传入的必须是long *指针,与CURLINFO_STRING/CURLINFO_OFF_T等类型不可混用,否则会因类型掩码不匹配导致CURLE_BAD_FUNCTION_ARGUMENT

实战建议

  1. 缓存场景:结合CURLOPT_TIMECONDITION做增量下载或缓存校验时,务必在传输后检查CURLINFO_CONDITION_UNMET,避免把 304 空响应误判为失败。
  2. 条件与 Range 互斥:从 lib/http.c 的源码可以看出,设置了时间条件且同时设置 Range 时,客户端侧不会模拟 304,判定路径会有差异,两者同时使用需谨慎。
  3. 时间戳一致性CURLOPT_TIMEVALUE使用 Unix 秒数,比较的是 UTC 时间,构造时间戳时注意时区换算,防止因时区偏移导致条件判断与预期不符。
  4. 协议适用性:官方文档声明该选项仅适用于 HTTP,但仓库源码显示 FTP(MDTM 路径)与 FILE(stat 路径)同样会置位timecond标志,因此在 FTP/FILE 场景下该选项同样具备参考价值。

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询