curl `--retry-all-errors` 实战解析:让任意错误都触发重试的“重锤“选项
curl--retry-all-errors实战解析让任意错误都触发重试的重锤选项【免费下载链接】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本篇以 curl 官方命令行选项文档 retry-all-errors.md 为主体完整覆盖--retry-all-errors的语义、适用边界与使用禁忌并结合 tool_operate.c 中的retrycheck()判定链、tool_main.h 中的退避常量以及仓库内真实测试用例讲解这一选项在源码层面何时重试、等多久、如何清理已写入的数据。读完后你将掌握如何把它与--retry、--fail、--retry-delay正确组合以及为什么官方明确警告不要把它写进curlrc。一、选项定位--retry-all-errors是什么根据官方选项文档docs/cmdline-opts/retry-all-errors.md--retry-all-errors的定义是Retry on any error. This option is used together with--retry.即对任何错误都进行重试且必须与--retry num配合使用才生效。选项元数据显示它自curl 7.71.0引入分类为curl仅命令行工具支持不属于 libcurl API类型是布尔开关典型用法为curl --retry 5 --retry-all-errors $URL官方文档把它称为重试机制里的 sledgehammer大锤并给出三条明确的纪律不要默认使用——尤其是不要写进你的curlrc因为它可能带来发送/接收重复数据等意外后果不要与重定向redirected的输入或输出一起使用如果你有特定的错误场景要处理更好的做法是用 shell 脚本单独处理而不是无差别地全量重试。二、它到底在哪些错误上加戏与普通重试的判定链对比先看基准行为。按 retry.md 的定义--retry只针对瞬态错误重试瞬态错误包括超时类timeoutFTP 4xx 响应码HTTP 408、429、500、502、503、504、522、524 响应码。而在命令行工具源码 src/tool_operate.c 中重试原因被枚举为enum retryreason { RETRY_NO, RETRY_ALL_ERRORS, RETRY_TIMEOUT, RETRY_CONNREFUSED, RETRY_HTTP, RETRY_FTP };retrycheck()tool_operate.c按顺序做判定超时类CURLE_OPERATION_TIMEDOUT、CURLE_COULDNT_RESOLVE_HOST、CURLE_COULDNT_RESOLVE_PROXY、CURLE_FTP_ACCEPT_TIMEOUT→RETRY_TIMEOUT连接被拒仅当同时开启了--retry-connrefused且CURLINFO_OS_ERRNO为SOCKECONNREFUSED→RETRY_CONNREFUSED见 retry-connrefused.mdHTTP 瞬态码传输成功CURLE_OK时检查 408/429/500/502/503/504/522/524 →RETRY_HTTP或者--fail已开启且结果为CURLE_HTTP_RETURNED_ERROR时也进入该分支FTP 4xxFTP/FTPS 方案下响应码 4xx →RETRY_FTP。而--retry-all-errors的介入点在这套判定链的最末尾是一句兜底逻辑tool_operate.cif(result !reason config-retry_all_errors) reason RETRY_ALL_ERRORS;含义非常清晰只要结果是非零错误、且前面所有具体规则都没有命中开启该选项后就一律升级为可重试。这就是any error的实现本质——它不是新增一套判定而是把其余所有未分类的错误整体纳入重试范围例如 SSL 握手失败、写文件失败、协议错误等在特定情形下都可能触发额外尝试。控制台也会如实标注这类重试的来源retry_sleep()中打印原因文案为(retrying all errors)tool_operate.c例如Problem (retrying all errors). Retrying in 1 second. 4 retries left.。三、退避策略重试之间等多久无论错误属于哪一类等待时间都由retry_sleep()tool_operate.c统一计算常量定义在 src/tool_main.h#define RETRY_SLEEP_DEFAULT 1000L /* ms */ #define RETRY_SLEEP_MAX 600000L /* ms 10 minutes */第一次重试前等待1 秒此后每次翻倍直到封顶10 分钟之后保持 10 分钟固定间隔——这正是 retry.md 描述的指数退避若响应头携带Retry-After:curl7.66.0 起会优先按该值等待且若加上该等待会超出--retry-max-time的总时限则直接放弃重试--retry-delay会禁用指数退避改用固定延时见 retry-delay.md--retry-max-time限制所有重试的总耗时上限见 retry-max-time.md。也就是说--retry-all-errors只改变哪些错误会触发重试退避节奏、次数上限、总时限仍完全由--retry家族控制。四、核心风险重试前对输出数据的处理官方警告的根源这是原文档着重强调的部分也是最容易踩坑的部分。服务端兼容性处理curl 试图让失败的传输尽可能像它最初开始的方式一样重试。实现上重试前如果已经向输出文件写入了部分数据curl 会执行截断——retrycheck()中只截断常规文件命名管道、字符设备不可截断并打印Throwing away N bytes提示tool_operate.c截断失败则直接报CURLE_WRITE_ERROR放弃重试。但管道和 shell 重定向无法重置如果输出被重定向到| 管道或 文件这些数据流不会被清空。官方文档因此发出明确警告We strongly suggest you do not parse or record output via redirect in combination with this option, since you may receive duplicate data.即不要一边用 shell 重定向收集输出一边开--retry-all-errors否则重试成功后你拿到的可能是半份 整份的重复拼接数据。还有一个值得注意的细节从源码结构看重试前并非一律丢弃已下载数据。is_outfile_auto_resumable()tool_operate.c会在满足严格条件下载场景、普通文件、非上传、结果为 GET 等下结合服务端Accept-Ranges: bytes或206 Partial Content响应把已收字节数作为断点续传起点CURLOPT_RESUME_FROM_LARGE保留下来而不是截断丢弃。这解释了为什么官方文档特别点出截断仅针对-o写出的文件也为长文件下载的自动续传重试提供了底层依据。五、想让 4xx/5xx 也重试与--fail组合原文档最后一段点出了--retry-all-errors的一个常见误解来源By default curl does not return an error for transfers with an HTTP response code that indicates an HTTP error, if the transfer was successful. For example, if a server replies 404 Not Found and the reply is fully received then that is not an error.默认情况下只要响应体完整收完404 Not Found在 curl 眼里就不是错误结果码为CURLE_OK。单独使用--retry时只有上文的瞬态 HTTP 码会触发重试大多数 4xx如 404不在其列。因此文档给出的方案是If you want to retry on all response codes that indicate HTTP errors (4xx and 5xx) then combine with--fail.--fail-f的作用是让 400 及以上的响应直接以错误码 22CURLE_HTTP_RETURNED_ERROR失败见 fail.md随后retrycheck()中config-fail (result CURLE_HTTP_RETURNED_ERROR)这一分支成立任意 4xx/5xx 都会进入 HTTP 重试判定。典型组合# 4xx/5xx 一律视为错误并重试 5 次 curl --fail --retry 5 $URL # 任何错误都重试含非 HTTP 错误再叠加对 4xx/5xx 的覆盖 curl --fail --retry 5 --retry-all-errors $URL注意一个边界--fail把 4xx/5xx 变成错误后走的是RETRY_HTTP分支而--retry-all-errors兜底分支处理的是其他所有非零结果码两者互补。六、源码中的选项接入路径该选项在命令行工具中的完整链路很短参数注册src/tool_getparam.c 中注册为布尔参数{retry-all-errors, ARG_BOOL, , C_RETRY_ALL_ERRORS}参数生效src/tool_getparam.c 中case C_RETRY_ALL_ERRORS: config-retry_all_errors toggle;写入每个 URL 的操作配置判定消费retrycheck()末尾的兜底分支读取config-retry_all_errorstool_operate.c。由此可以推断该开关是**逐传输per-operation**的作用于命令行工具的操作层而不改变 libcurl 库本身的重试语义。七、仓库测试用例印证的实际行为仓库中的测试数据为这一选项的行为提供了可验证依据tests/data/test1909--retry 1 --retry-all-errors -o ...名称为 HTTP GET --retry-all-errors to overcome partial transfer验证部分传输中断后自动重试完成tests/data/test3036--no-clobber --output-dir -OJ --retry 1 --retry-all-errors验证目标文件已存在--no-clobber场景下重试与输出目录的交互tests/data/test1673上传时源文件不存在--upload-file AAAAAAAAAAA即使用--retry 5 --retry-all-errors也无法自愈最终以错误码 26CURLE_READ_ERROR退出——说明全量重试不等于无限自愈重试次数耗尽后 curl 仍会如实报错tests/http/test_05_errors.py集成测试中test_05_06_retry_502验证 502 会重试而test_05_08_retry_401名称 Get, retry on 401, not happening验证不带--fail时 401 不会被当作错误而触发重试与第五节的结论一致。八、使用建议速查场景建议偶发超时、502/503 等瞬态错误仅用--retry N无需--retry-all-errors需要重试 4xx/5xx--fail --retry N或再加--retry-all-errors网络环境极不稳定、想能成就行--retry N --retry-all-errors --retry-delay 1且输出写到-o文件而非管道/重定向全局默认行为不要写入curlrc官方明确警告有特定错误语义要处理用 shell 脚本捕获退出码分类处理更可控一句话总结--retry-all-errors是把--retry的判定范围从瞬态错误扩展到任意错误的兜底开关代价是重复数据风险与不可自愈错误的无效重试正确姿势是限定输出到-o文件、控制重试次数与总时限并只在确有价值的场景下显式使用。【免费下载链接】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),仅供参考