ARTICLE DETAIL

资讯详情

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

深入解读 curl `--fail-with-body`:HTTP 出错时保留响应体并返回退出码 22

深入解读 curl `--fail-with-body`:HTTP 出错时保留响应体并返回退出码 22 深入解读 curl--fail-with-bodyHTTP 出错时保留响应体并返回退出码 22【免费下载链接】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导读--fail-with-body是 curl 命令行的 HTTP 选项用于在服务器返回 4xx/5xx 错误响应时让 curl 以退出码 22 报告失败同时仍然保留并输出服务器返回的错误响应正文。本篇文章围绕该选项的语义、与--fail的区别、源码级工作机制、脚本中的实战用法及测试验证展开阅读后你将能够在自动化脚本与排障流程中精准控制报错与留证行为。curl 默认如何看待 HTTP 状态码HTTP 协议中4xx/5xx 状态码表示服务器无法正常交付文档如 404 Not Found、500 Internal Server Error此时服务器通常会返回一段说明性质的正文常常是 HTML会描述出错原因及更多信息。关键认知默认情况下curl 不把 HTTP 状态码视为失败。也就是说执行curl https://example.com/not-exist收到 404 时命令依然以 0成功退出把那段错误 HTML 原样输出到 stdout。这一默认行为在 fail.md 中也有明确说明By default, curl does not consider HTTP response codes to indicate failure.脚本因此常常无法简单依据退出码判断 HTTP 层面是否出错——这正是--fail与--fail-with-body这类选项存在的意义。--fail-with-body的语法与行为该选项的官方定义文件位于 fail-with-body.md其 front-matter 记录了完整的选项元数据属性值长选项名--fail-with-body短选项名无适用协议HTTP帮助文本Fail on HTTP errors but save the bodyHTTP 出错时失败但保留正文分类http output加入版本7.76.0互斥选项fail参数类型boolean开关型不带参数值核心语义根据原文档fail-with-body.md该选项的作用是Return an error on server errors where the HTTP response code is 400 or greater. … This option allows curl to output and save that content but also to return error 22.即当 HTTP 响应码大于等于 400时curl 将本次传输判定为失败与不保存内容的失败模式不同服务器返回的错误正文照常被输出/保存例如输出到 stdout 或写入-o指定的文件命令最终返回错误码 22对应 libcurl 的CURLE_HTTP_RETURNED_ERROR。因此在需要既知道请求失败了又能拿到错误页正文用于分析根因的场景例如打印 CDN/网关错误页、留存 WAF 拦截响应中--fail-with-body是比--fail更合适的选择。基本用法# 服务器返回 4xx/5xx 时命令退出码为 22同时正文仍会输出 curl --fail-with-body https://example.com/does-not-exist--fail-with-body不接收参数值可与 URL 任意组合也适用于多次传输的批量场景front-matter 中Multi: boolean表示它可在同一命令中对每个 URL 独立生效。与--fail的区别及互斥关系--fail短选项-f自 curl 4.0 时代就已存在见 fail.md针对完全相同的条件HTTP 响应码 400让 curl 失败并返回错误 22区别在于--fail会阻止正文输出Fail with error code 22 and with no response body output at all for HTTP transfers returning HTTP response codes at 400 or greater.两者的行为对比行为--fail-f--fail-with-bodyHTTP 响应码 400 时失败是是失败时返回退出码2222是否输出/保存错误正文否完全不输出是正文保留在命令行加入的版本4.07.76.0实现层面通过 libcurl 的CURLOPT_FAILONERROR提前中止传输传输完整跑完后在工具层检查状态码再报错互斥与告警两个选项互为互斥Mutexed: fail / fail-with-body。同时指定时后指定的会撤销先指定的并打印告警。命令行解析逻辑位于 src/tool_getparam.ccase C_FAIL: /* --fail without body */ if(toggle (config-fail FAIL_WITH_BODY)) warnf(--fail deselects --fail-with-body here); config-fail toggle ? FAIL_WO_BODY : FAIL_NONE; break; case C_FAIL_WITH_BODY: /* --fail-with-body */ if(toggle (config-fail FAIL_WO_BODY)) warnf(--fail-with-body deselects --fail here); config-fail toggle ? FAIL_WITH_BODY : FAIL_NONE; break;例如执行curl --fail-with-body --fail URL工具会提示Warning: --fail deselects --fail-with-body here最终按--fail语义处理。该行为由测试 tests/data/test360 验证该测试同时传入两个选项并断言 stderr 中出现上述警告。源码级工作机制状态枚举三种失败模式curl 工具层用一个枚举区分三种状态定义在 src/tool_cfgable.h#define FAIL_NONE 0 #define FAIL_WITH_BODY 1 #define FAIL_WO_BODY 2FAIL_NONE默认状态HTTP 状态码不视为失败FAIL_WITH_BODY由--fail-with-body设置FAIL_WO_BODY由--fail/-f设置。选项名到枚举的映射在 src/tool_getparam.c 中登记其中--fail对应短选项f、--fail-with-body无短选项{fail, ARG_BOOL, f, C_FAIL}, {fail-early, ARG_BOOL, , C_FAIL_EARLY}, {fail-with-body, ARG_BOOL, , C_FAIL_WITH_BODY},两条截然不同的实现路径--failFAIL_WO_BODY的落实位置在 libcurl 库层。工具把配置转成 libcurl 选项时src/config2setopts.c执行my_setopt_long(curl, CURLOPT_FAILONERROR, config-fail FAIL_WO_BODY);也就是说只有FAIL_WO_BODY才会把 libcurl 的CURLOPT_FAILONERROR置 1使传输在库内被提前判定失败见 lib/setopt.c 对CURLOPT_FAILONERROR的注释Do not output the 400 error code HTML-page, but instead only return error。底层判定函数是 lib/http.c 的http_should_fail()。--fail-with-bodyFAIL_WITH_BODY则完全不同它不设置CURLOPT_FAILONERROR因此整个 HTTP 传输包括错误正文的接收与写出会正常跑完正文被完整保存随后在传输后置检查post_check_result()中补做状态码判定见 src/tool_operate.celse if(config-fail FAIL_WITH_BODY) { /* if HTTP response 400, return error */ long code 0; curl_easy_getinfo(per-curl, CURLINFO_RESPONSE_CODE, code); if(code 400) { if(!global-silent || global-showerror) curl_mfprintf(tool_stderr, curl: (%d) The requested URL returned error: %ld\n, CURLE_HTTP_RETURNED_ERROR, code); return CURLE_HTTP_RETURNED_ERROR; } }这段代码揭示了--fail-with-body的内部原理传输完成后通过curl_easy_getinfo(per-curl, CURLINFO_RESPONSE_CODE, code)取回最终 HTTP 响应码若code 400向 stderr 打印curl: (22) The requested URL returned error: 状态码返回CURLE_HTTP_RETURNED_ERROR即退出码22。因为检查发生在后置阶段正文此时早已写入输出目标stdout 或-o指定的文件从而实现了出错但留证。相反--fail的CURLOPT_FAILONERROR路径会在收到错误状态码时让 libcurl 提前中止并把整个响应当作失败丢弃lib/http.c 等处正文不再输出。退出码 22 是什么退出码 22 对应 libcurl 错误常量CURLE_HTTP_RETURNED_ERROR定义于 include/curl/curl.h其人类可读描述为 HTTP response code said error见 lib/strerror.c。历史上它还保留着别名CURLE_HTTP_NOT_FOUNDinclude/curl/curl.h。因此脚本中可统一判断curl --fail-with-body https://api.example.com/order/123 -o error_page.html if [ $? -eq 22 ]; then echo HTTP 层请求失败错误页已保存到 error_page.html 供排查 filibcurl 层CURLOPT_FAILONERROR的边界行为理解差异的关键由于--fail-with-body走的是工具层后置检查对400无条件报错而--fail依赖库内CURLOPT_FAILONERROR的判定逻辑两者在少数边界场景下行为并不完全等价。理解库层逻辑有助于避免误用。http_should_fail()lib/http.c按序执行以下判断未开启CURLOPT_FAILONERROR一律不失败响应码 400永不失败断点续传场景若此前用Range/resume发起 GET 且收到416视为文件已下载完而非失败lib/http.c响应码 400且不是 401/407一律判定失败对于401认证失败/ 407代理认证失败需结合当前认证协商状态判断lib/http.c认证流程可能让这类状态码放行。这也是 fail.md 特别提醒的原因--fail并非万无一失尤其在涉及认证时401 与 407可能出现非成功响应码漏判。如果你在脚本中必须对任何400响应包括 401/407一律报错同时又要保留响应正文--fail-with-body那套跑完再查码的后置逻辑反而是更直接、更可预期的选择。实战用--fail-with-body完成出错留证的请求抓取并保存服务器错误页很多网关、WAF 或反代在 4xx/5xx 时返回自定义错误页正文里往往包含 trace/request-id 等排障线索。需要把这些正文留存curl --fail-with-body --silent --show-error \ https://api.example.com/users/42 \ -o response_body.txt成功状态码 400正文存入response_body.txt退出码 0失败状态码 400正文同样存入response_body.txt但退出码为 22stderr 打印curl: (22) The requested URL returned error: 404。对比--fail遇到错误时正文不会被保存response_body.txt将不存在或为空无法事后分析。检查头部/隐藏进度输出可与其他选项自由组合例如配合-i输出含响应头或--no-progress-meter以便于解析# 保留错误页正文的同时附带响应头适合调试重定向与缓存策略 curl --fail-with-body --no-progress-meter -i https://cdn.example.com/path/resource与--retry组合重试后仍然失败时也能留证--fail-with-body可与重试选项叠加。测试 tests/data/test1635 即验证了--retry 1 --fail-with-body在服务端返回 429含Retry-After并重试一次后的行为重试期间每次 429 响应正文都会被接收最终请求仍失败时退出码为 22。# 遇到 429/5xx 自动重试一次最终仍失败时保留最后一次错误正文 curl --fail-with-body --retry 1 --retry-delay 1 https://api.example.com/rate-limited断言服务器确实出错把HTTP 状态码转化为脚本可判定的退出码是 CI/CD、监控探针中的常见需求if curl --fail-with-body --silent http://internal.example.com/healthz -o /dev/null; then echo 健康检查通过 else echo 健康检查失败退出码 $?已输出错误详情 2 fi测试用例印证仓库为--fail-with-body提供了多组回归测试可作为理解其行为的权威参考测试文件验证内容tests/data/test349服务端返回HTTP/1.0 404时执行--fail-with-body断言退出码为22errorcode22/errorcode且该测试能正常接收 404 正文tests/data/test360同时传入--fail-with-body --fail断言 stderr 出现Warning: --fail deselects --fail-with-body here互斥告警tests/data/test361--fail-with-body在 HTTP 错误返回时连续两次多 URL/重复传输场景均正确报错tests/data/test1635--retry 1 --fail-with-body与 429 Retry-After的组合行为相关选项与进一步阅读fail.md--fail/-f报错但不输出正文的快速失败模式及其非万无一失401/407的注意点fail-early.md--fail-early注意它解决的是另一个维度的问题——在发生一次传输错误时尽早终止整体操作而非针对 HTTP 状态码libcurl 层面等价机制为CURLOPT_FAILONERROR在 curl_easy_setopt 选项索引 中可检索到对应条目想深入失败模式的完整实现可分别阅读工具层选项解析与互斥告警src/tool_getparam.c、src/tool_cfgable.h工具层后置状态码检查--fail-with-body的核心src/tool_operate.c库层快速失败判定CURLOPT_FAILONERROR的设置与消费分别在 src/config2setopts.c、lib/setopt.c 与 lib/http.c。小结--fail-with-bodycurl 7.76.0 起可用在--fail的基础上补上了正文留证的能力它不干预传输过程让服务器返回的错误页正常落盘再于传输完成后用CURLINFO_RESPONSE_CODE检查状态码对400的响应返回退出码 22CURLE_HTTP_RETURNED_ERROR。对需要自动化排障、抓取错误页根因信息的脚本而言它比--fail更实用理解它与CURLOPT_FAILONERROR库层判定的差异尤其是 401/407 与 416 的边界处理则能帮助你在具体场景中做出正确选择。【免费下载链接】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),仅供参考
返回列表