ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

curl `--etag-save` 参数完全指南:解析响应中的 HTTP ETag,配合 `--etag-compare` 实现高效的增量下载

curl `--etag-save` 参数完全指南:解析响应中的 HTTP ETag,配合 `--etag-compare` 实现高效的增量下载 curl--etag-save参数完全指南解析响应中的 HTTP ETag配合--etag-compare实现高效的增量下载【免费下载链接】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--etag-save file是 curl 命令行工具提供的一个 HTTP 专属参数自 7.68.0 版本引入其作用是把服务器在响应头中返回的 ETag实体标签HTTP 缓存相关的标识头解析出来并写入指定文件。它通常与--etag-compare配对使用先用旧 ETag 发起条件请求若资源发生变化再顺手把新 ETag 落盘从而实现资源未变不重复下载、资源已变自动更新缓存标识的增量抓取方案。本文基于当前仓库 docs/cmdline-opts/etag-save.md 展开并深入到 src/ 目录下 curl 工具层源码与 tests/data 测试用例帮助你在脚本、爬虫与缓存同步场景中正确、高效地使用这一组选项。一、--etag-save是什么把 HTTP ETag 落盘ETagEntity Tag是 HTTP 响应头中的缓存相关标识形如ETag: 33a64df5-8b6f-4d1e-b1c3-8a3f0f2c0a11服务器通常用它标记某个资源的版本或内容指纹。当响应中带有ETag头时使用--etag-save可以让 curl 在传输结束后把该值写入你指定的文件。选项元数据源自文档头部的 front matter属性值长选项--etag-save参数file目标文件名说明解析到来的 ETag 并保存到文件适用协议HTTPHTTP/HTTPS引入版本7.68.0分类http多请求语义single每条命令行只允许配合单个 URL基本示例即文档中的 Examplecurl --etag-save storetag.txt https://example.com/resource执行后服务器响应中的 ETag 值会被写入storetag.txt。当前仓库版本为 8.22.0-DEV见 include/curl/curlver.h下文涉及的行为均以本仓库代码为准。二、核心行为规则根据 etag-save.md 的定义该选项遵循以下行为只处理单个 URL--etag-save只能与一个 URL 搭配使用。若在同一命令行中给出多个 URL参数解析会直接报错详见下文源码分析。服务器未返回 ETag 时创建空文件如果响应里没有 ETag 头curl 会创建一个空的目标文件该行为由打开文件时的创建逻辑保证见下文etag_store分析。保存内容为精简后的 ETag 值写入文件的是去除行首行尾空白后、以单个换行符结尾的 ETag 文本方便下次读取后直接拼装成请求头。-可表示标准输出目标文件参数传-时ETag 将输出到 stdout测试 tests/data/test321 用--etag-save - out验证了追加到文件的重定向用法tests/data/test1619 验证了-O --etag-save -的组合。三、与--etag-compare配对条件请求与增量下载文档强调--etag-save最典型的用法是与 --etag-compare 使用同一个文件名、出现在同一条命令行中从而用已保存的 ETag 构造If-None-Match条件请求头避免重复下载未变化的资源若资源确实变化服务器返回新的 ETag把新值保存下来供下次使用。# 第一次无条件下载并把 ETag 存入 etag.txt curl --etag-save etag.txt -o data.bin https://example.com/large-file # 之后每次携带旧 ETag 发起条件请求变化时才下载正文并刷新 etag.txt curl --etag-compare etag.txt --etag-save etag.txt -o data.bin \ https://example.com/large-file当资源未变化时服务器返回304 Not Modified正文不会被传输本地输出文件保持原样当资源变化时服务器返回200 OK及新的ETag头curl 一边下载正文一边把新 ETag 覆盖写入etag.txt从而完成缓存标识的自动滚动更新。测试 tests/data/test343 与 tests/data/test344 专门验证了--etag-compare与--etag-save同时使用以保存新 ETag的场景。配套的--etag-compare其文档见 etag-compare.md补充了以下约定它会读取文件内容并构造自定义的If-None-Match: etag请求头为保证结果正确文件应只含单行ETag 文本文件不存在或为空时被视为空 ETag此时发送的请求头为If-None-Match: 测试 tests/data/test341 验证了这一分支。四、细化的边界条件与注意事项综合文档与仓库测试使用时有几点值得注意2xx/3xx 响应才会处理 ETag从实现看ETag头只在 2xx 与 3xx 响应中被采集见下文回调逻辑这与文档响应中通常返回的缓存头的定位一致。头部匹配不区分大小写无论服务器发送ETag:还是etag:curl 都能识别源码注释即标明 case insensitive。只针对 HTTP(S)该选项的协议字段为 HTTP回调中也先判断了传输协议是否为http/https才处理 ETag 头。单 URL 强约束命令行同时给多个 URL 会直接报错测试 tests/data/test484 与 tests/data/test485 覆盖多 URL 报错路径。目录不存在时默认失败若目标文件所在目录不存在curl 会发出警告并跳过该传输测试 tests/data/test370 与 tests/data/test369 验证了目录不存在的失败/跳过行为除非配合--create-dirs。curl 8.12.0 起--create-dirs支持自动建目录文档明确指出自 curl 8.12.0 起使用--create-dirs选项可以为--etag-save提供的路径自动创建缺失的目录层级例如curl --etag-save /tmp/cache/v1/etag.txt --create-dirs https://example.com/file当/tmp/cache/v1/尚不存在时curl 会先调用create_dir_hierarchy()逐级创建再打开文件。测试 tests/data/test693 正是把--etag-save指向%LOGDIR/moo/boo/etag%TESTNUMBER多级不存在的目录并配合--create-dirs进行验证。而 --create-dirs 本身的完整语义创建输出所需目录可查阅其独立文档。五、源码级实现解析从参数解析到落盘为了准确理解行为我们沿 curl 工具层的调用链走一遍实现。1. 参数登记与单 URL 校验在 src/tool_getparam.c 中两个选项注册为文件参数{etag-compare, ARG_FILE, , C_ETAG_COMPARE}, {etag-save, ARG_FILE, , C_ETAG_SAVE},处理分支中先检查 URL 数量src/tool_getparam.ccase C_ETAG_SAVE: /* --etag-save */ if(urls) { errorf(The etag options only work on a single URL); return PARAM_BAD_USE; } err getstr(config-etag_save_file, nextarg, DENY_BLANK);也就是说一旦命令行已累积超过一个 URL再出现 etag 相关选项就会立即报错同理若选项出现时已解析到多个 URL如 src/tool_getparam.c 处的整体校验也会被拒绝。2. 打开目标文件etag_store()src/tool_operate.c 中的etag_store()负责真正打开文件static CURLcode etag_store(struct OperationConfig *config, struct OutStruct *etag_save, bool *skip) { if(config-create_dirs) { CURLcode result create_dir_hierarchy(config-etag_save_file); if(result) return result; } /* open file for output: */ if(strcmp(config-etag_save_file, -)) { FILE *newfile curlx_fopen(config-etag_save_file, ab); if(!newfile) { warnf(Failed creating file for saving etags: \%s\. Skip this transfer, config-etag_save_file); *skip TRUE; return CURLE_OK; } ...实现要点先用ab追加 二进制模式打开文件文件不存在时由fopen创建——这正是服务器无 ETag 也生成空文件的机制来源打开失败时不视为致命错误而是警告并跳过该次传输文件参数为-时复用已初始化为 stdout 的流并切换为二进制模式实现向标准输出打印 ETag。3. 头部回调中采集 ETagtool_header_cb()与save_etag()curl 通过CURLOPT_HEADERFUNCTION回调处理每个响应头。src/tool_cb_hdr.c 的tool_header_cb()中采集逻辑大致如下curl_easy_getinfo(per-curl, CURLINFO_SCHEME, scheme); scheme proto_token(scheme); if((scheme proto_http || scheme proto_https)) { long response 0; curl_easy_getinfo(per-curl, CURLINFO_RESPONSE_CODE, response); if((response / 100 ! 2) (response / 100 ! 3)) /* only care about etag and content-disposition headers in 2xx and 3xx */ ; else if(per-config-etag_save_file etag_save-stream checkprefix(etag:, str)) { /* 大小写不敏感前缀匹配 */ size_t rc save_etag(str[5], end, etag_save); ...可见回调先通过CURLINFO_SCHEME确认协议为http/https只有状态码为 2xx/3xx 的响应才会被检查用checkprefix(etag:, str)底层为大小写不敏感的curl_strnequal参见 lib/strcase.h匹配响应头名字。真正落盘的save_etag()src/tool_cb_hdr.c会做三件事去除 ETag 值首尾空白、先把已有内容截断为 0 再写入新值避免读到旧 ETag 的残留内容注释原文 Truncate regular files to avoid stale etag content、以换行结尾并 flush。这也解释了为何同一命令中--etag-compare与--etag-save共用同名文件是安全的每次收到新 ETag 都会先清空文件再写入最新值。4. 读取旧 ETagetag_compare()配套的 src/tool_operate.c 中etag_compare()负责把文件里的 ETag 变成请求头if((PARAM_OK file2string(etag_from_file, file)) etag_from_file) { char *h curl_maprintf(If-None-Match: %s, etag_from_file); ... } else header curlx_strdup(If-None-Match: \\);即文件可读且非空时发送If-None-Match: 内容文件不存在或为空时降级为If-None-Match: 随后通过add2list()加入自定义请求头列表由 libcurl 随请求一并发出。服务器据此决定返回304 Not Modified未变化还是200 OK 新ETag已变化。六、测试验证行为有据可查仓库 tests/data 中有一系列专门测试覆盖本功能可作为行为契约参考测试文件验证点tests/data/test339--etag-save正确保存 ETag 到文件tests/data/test1566--etag-compare收到 304 时不应改写输出文件tests/data/test341配合--etag-compare的文件不存在时按空 ETag 处理发送If-None-Match: tests/data/test342--etag-compare正确生成If-None-Match请求头tests/data/test343、tests/data/test344、tests/data/test3204--etag-compare--etag-save组合保存新 ETagtests/data/test321、tests/data/test1619--etag-save -输出到 stdouttests/data/test693--etag-save到不存在目录 --create-dirs自动建目录tests/data/test370、tests/data/test369目标目录不存在时失败/跳过的行为tests/data/test484、tests/data/test485多 URL 时 etag 选项报错例如 tests/data/test1566 中服务端返回HTTP/1.1 304 Not Modified同时验证了请求方发出的If-None-Match: 123456头以及本地输出文件内容在 304 后保持downloaded already不变——这是条件请求不重复下载的最直接佐证。七、典型实战场景小结把文档要点与源码行为结合起来一套可落地的脚本模式如下#!/bin/sh # 增量同步脚本仅当远端资源变化时才下载正文 urlhttps://example.com/releases/app-archive.bin tagfile/var/cache/app-etag.txt # 首次运行若 tagfile 不存在--etag-compare 自动按空 ETag 处理全量下载 curl --etag-compare $tagfile \ --etag-save $tagfile \ --create-dirs \ -o /var/cache/app-archive.bin \ $url资源未变服务器返回 304正文不传输app-archive.bin保持不变etag.txt内容不变资源已变curl 下载新正文并把新 ETag 覆盖写入etag.txt下一次自动携带最新值--create-dirs8.12.0确保/var/cache/等缓存目录即使首次不存在也能被自动创建全程遵守etag 选项仅适用于单个 URL的约束需要并发同步多个资源时请为每个 URL 单独发起一次 curl 调用。延伸阅读配套选项说明--etag-compare、--create-dirs实现源码src/tool_cb_hdr.csave_etag/头部回调、src/tool_operate.cetag_compare/etag_store、src/tool_getparam.c参数表行为契约测试tests/data/test343、tests/data/test1566、tests/data/test693版本说明--etag-save/--etag-compare自 curl 7.68.0 提供--create-dirs对--etag-save的支持自 curl 8.12.0 生效当前仓库主干版本见 include/curl/curlver.h。【免费下载链接】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),仅供参考
返回列表