DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

curl 多个 URL 共用 ETag 文件后只剩一个标签

ETag 文件只保存单个资源的状态。将多 URL 请求拆开,为每个资源隔离标签与正文,并正确处理 304 和下载失败。

一次 curl 命令下载两个 URL,同时使用 --etag-compare .etags --etag-save .etags,下载后 .etags 却只剩一个值。再次执行时,有些资源仍被重新下载;加上 --parallel 后,还可能出现不同请求争用同一文件的情况。

这两个选项使用的是单个资源的 ETag 状态文件,不是“URL 到 ETag”的索引数据库。一个文件只有一条标签,不能表达两个独立资源各自的版本。当前用法要求每次只处理一个 URL。

下面针对 HTTP/HTTPS 的条件 GET 请求。ETag 选项从 curl 7.68.0 起提供;示例应使用受支持的新版本。这里解决多资源共用状态的问题,不把 ETag 当作下载文件的完整性校验值。

同一个标签不能分发给所有 URL

--etag-compare 从文件读取 ETag,并在请求中发送 If-None-Match。--etag-save 则保存响应里的 ETag。标签需要与具体资源及其响应表示关联,不能因为文件都来自同一个域名,就给它们共用一个值。

例如下面是两份独立状态的示意:

https://downloads.example.com/a.json  -> a.etag
https://downloads.example.com/b.json  -> b.etag

a.etag 中的值应只用于对应的 a.json。当服务器根据请求头、账户或其他条件返回不同表示时,也要维持相同请求条件,不能把不同账户得到的标签和文件混在一起。

不应把多行 ETag 塞进同一个文件期待 curl 自动匹配 URL。比较文件需要只包含一行所需标签;重复写多个 --etag-save 也不是为每个 URL 自动分配一个文件的可靠方式。

每个资源单独请求,状态路径也分开

先在自己控制的工作目录创建专用测试目录,目录名必须尚不存在:

mkdir ./etag-check-01

确认创建成功后,分别处理两个获准下载的资源:

curl --fail --silent --show-error \
  --etag-compare ./etag-check-01/a.etag \
  --etag-save ./etag-check-01/a.etag \
  --output ./etag-check-01/a.json \
  --write-out '%{http_code}\n' \
  'https://downloads.example.com/a.json'

curl --fail --silent --show-error \
  --etag-compare ./etag-check-01/b.etag \
  --etag-save ./etag-check-01/b.etag \
  --output ./etag-check-01/b.json \
  --write-out '%{http_code}\n' \
  'https://downloads.example.com/b.json'

域名、路径和文件名都是示例;先确认第一条请求的退出状态及结果,再判断是否继续。没有比较文件或文件为空时,curl 将其视为空 ETag;首次调用不能据此期待服务器返回 304。

同一个资源在一次请求中使用同名的 compare/save 文件是受支持的用法,问题在于多个资源共用它。不同任务可以各自处理不同资源,但同一资源的状态与正文不能被多个并发进程无协调地读写。测试目录也应按账户和任务隔离。

304 需要已有正文配合

200 响应通常携带正文;条件请求返回 304 Not Modified 时,不会重新提供完整资源正文。只有本地已经有与该请求和标签对应的有效文件,304 才能用于继续复用缓存。

若只保留了 ETag、正文却被删除,发送旧标签可能得到 304,却无法恢复缺失的文件。这时应对该资源发起不带旧条件的完整下载,并在成功后重新建立正文与标签的对应关系,不要把 304 当成“文件一定在本地”。

curl 的两个 ETag 选项也不负责事务式管理缓存。如果传输中断、磁盘写入失败或正文验证失败,应保留此前的好版本,不把本次标签与不完整正文作为新缓存发布。正式下载任务需要先写入候选路径,核对退出状态、响应状态、内容和需要的校验结果,再协调替换该资源的正文与状态文件;上面的独立测试目录不应直接替代这套更新流程。

服务器没有发送 ETag 时,save 文件可以是空的。这与多 URL 相互覆盖不是同一个原因,应先看各资源自己的响应,不根据“文件存在”判断缓存已经可用。不要去掉 ETag 值中的双引号或弱验证前缀来尝试修复。

验收分别针对两个资源

先用两个可控资源建立各自的正文和标签,再重复请求,观察每个请求的响应状态。让其中一个资源发生受控变化后,检查它的状态文件和正文是否更新,另一个资源是否仍保持自己的对应关系。所有结果都应按 URL 分别判断,不能只看整条多 URL 命令的最后一次输出。

如果旧脚本已经共用过 .etags,停止并发使用它,保留现有文件供比对,为每个资源重新建立已验证的状态。回退改动时恢复旧脚本的其他请求设置,但不要继续把旧的共享 ETag 文件当作有效多资源缓存;也无需清空所有下载物或关闭服务端缓存。