如果 HTTP 状态代码不是 200,我是否可以使 cURL 失败并且退出代码不同于 0?

kno*_*cte 389 curl stdout http-status-code-500 exit-code

我一直假设当 curl 收到 HTTP 500 响应时,它会返回一个退出代码,这意味着失败 (!= 0),但事实并非如此。

如果 HTTP 状态代码不是 200,有没有一种方法可以使 cURL 失败,并且退出代码不同于 0?我知道我可以使用,-w "%{http_code}"但这将它放在 STDOUT 中,而不是作为退出代码(此外,我也对捕获输出感兴趣,我不想重定向到文件,而是重定向到屏幕)。

ram*_*ion 413

curl --fail 做你想要的一部分:

来自man curl

-f, --fail

(HTTP) 在服务器错误时静默失败(根本没有输出)。这样做主要是为了更好地启用脚本等以更好地处理失败的尝试。在正常情况下,当 HTTP 服务器无法传递文档时,它会返回一个 HTML 文档,说明如此(通常也描述了原因等等)。此标志将阻止 curl 输出并返回错误 22。

这种方法不是万无一失的,有时会漏掉不成功的响应代码,尤其是在涉及身份验证时(响应代码 401 和 407)。

但它阻止输出到屏幕。

  • @wisbucky 301 不是错误,而是重定向状态代码。错误是 4xx 和 5xx 状态代码。 (12认同)
  • @rogerdpack tl;dr 在检测到错误响应时确实返回非零值,但它不会让 OP 捕获响应 (10认同)
  • 这不会捕获 HTTP 301 Move Permanently。curl 仍然给出退出代码 0。 (6认同)
  • 那么它的哪些部分做了哪些不做呢? (4认同)
  • @wisbucky 在 HTTP 错误代码上退出非零 * 和 * 正确处理 HTTP 重定向使用 `curl -f -L` 并查看 [这个问题](/sf/ask/1293228331/ -to-follow-redirects-with-command-line-curl) 以获取有关“-L”功能的详细信息。 (2认同)

Den*_*nis 118

如果只想显示卷曲页面的内容,可以这样做:

STATUSCODE=$(curl --silent --output /dev/stderr --write-out "%{http_code}" URL)

if test $STATUSCODE -ne 200; then
    # error handling
fi
Run Code Online (Sandbox Code Playgroud)

这会将页面内容写入 STDERR,同时将 HTTP 状态代码写入 STDOUT,因此可以将其分配给变量STATUSCODE

  • 作为一个微小的变化,这在将响应重定向到 stdout 而不是 stderr 时捕获变量中的代码:`{ code=$(curl ... as above ...); } 2>&1` 诀窍是`{ ... } 2>&1` 允许重定向,同时不会像`( ... )` 那样产生不同的shell。 (9认同)
  • @ghti:仅支持无符号的 8 位退出代码,因此可能会有点混乱。 (4认同)
  • 如果我想在失败时输出响应 *(non 200)*,但从脚本中返回非“0”状态代码,该怎么办? (3认同)
  • 啊,对了——代码会以 8 位换行,所以错误 404 变成退出值 148,500 变成 244。确实令人困惑!:-) (3认同)
  • @Justin:`if [ "$statuscode" -ne 200 ] 呢?然后退出“$statuscode”;菲`? (2认同)

小智 78

我能够使用标志的组合来做到这一点:

curl --silent --show-error --fail URL
Run Code Online (Sandbox Code Playgroud)

--silent隐藏进度和错误
--show-error显示由--silent
--fail隐藏的错误消息,当请求失败时返回退出代码 > 0

  • 这不显示服务器回复。我不是 OP,但我怀疑他想查看服务器中返回的任何错误消息。除了`--silent --show-error --fail` 与`-f/--fail` 的工作原理相同。 (19认同)
  • 公平地说,@wisbucky,原始问题指出 _"[...] 如果 HTTP 状态代码不是 200"_。之前任何地方都没有提到“错误”。 (7认同)
  • @wisbucky 301 不是错误,而是重定向状态代码。错误是 4xx 和 5xx 状态代码。 (3认同)
  • @M.Justin 根据 curl 手册页:此方法不是故障安全的,有时会漏掉不成功的响应代码,尤其是在涉及身份验证时(响应代码 401 和 407)。 (2认同)

phe*_*mer 21

使用--fail-with-body. curl当响应代码 >=400 时,这将导致以状态代码 22 退出。

请注意,此标志是全新的(截至 2021 年 2 月 15 日),并已添加到版本 7.76.0 中,该版本晚于 @rampion的回答。因此,它可能在您的系统上不可用。

https://curl.se/docs/manpage.html

-- 身体失败

(HTTP) 在 HTTP 响应代码为 400 或更大的服务器错误时返回错误)。在正常情况下,当 HTTP 服务器无法传递文档时,它会返回一个 HTML 文档,说明如此(通常也描述了原因等等)。此标志仍将允许 curl 输出和保存该内容,但也会返回错误 22。

这是 -f, --fail 的替代选项,它使 curl 在相同情况下失败但不保存内容。

另请参见 -f、--fail。在 7.76.0 中添加。

-f, --失败

(HTTP) 在服务器错误时静默失败(根本没有输出)。这样做主要是为了使脚本等能够更好地处理失败的尝试。在正常情况下,当 HTTP 服务器无法传递文档时,它会返回一个 HTML 文档,说明如此(通常也描述了原因等等)。此标志将阻止 curl 输出并返回错误 22。

这种方法不是万无一失的,有时会漏掉不成功的响应代码,尤其是在涉及身份验证时(响应代码 401 和 407)。

另见--fail-with-body。

  • 这确实是最好的答案。我刚刚使用预构建的二进制文件将容器上的curl更新为最新版本,并且“--fail-with-body”工作完美。谢谢。 (7认同)

小智 14

我最终根据Dennis 的回答得到了这个结果,这是一个快速的单行代码,对于非 200 状态代码失败,同时保留输出(到stderr):

[ $(curl ... -o /dev/stderr -w "%{http_code}") -eq 200 ]
Run Code Online (Sandbox Code Playgroud)


小智 8

如果请求失败,到目前为止提供的大多数答案都不会返回 HTTP 响应正文。如果您想打印退出代码的响应,并且如果 http 请求失败,退出代码为非零,请尝试以下操作:

curlf() {
  OUTPUT_FILE=$(mktemp)
  HTTP_CODE=$(curl --silent --output $OUTPUT_FILE --write-out "%{http_code}" "$@")
  if [[ ${HTTP_CODE} -lt 200 || ${HTTP_CODE} -gt 299 ]] ; then
    >&2 cat $OUTPUT_FILE
    return 22
  fi
  cat $OUTPUT_FILE
  rm $OUTPUT_FILE
}
Run Code Online (Sandbox Code Playgroud)

(除非你有 curl v7.76+。然后使用curl --fail-with-body.)

  • 遗憾的是,7.76 没有到达 macos,它似乎仍在使用 7.65.1 (2认同)

sor*_*rin 7

是的,有一种方法可以做到,但远非显而易见,因为它涉及 3 个卷曲选项:

curl -s --fail --show-error https://httpbin.org/status/200 > /dev/null
curl -s --fail --show-error https://httpbin.org/status/401 > /dev/null
curl -s --fail --show-error https://httpbin.org/status/404 > /dev/null
curl -s --fail --show-error https://bleah-some-wrong-host > /dev/null
Run Code Online (Sandbox Code Playgroud)

这确保了成功 (0) 仅在 curl 以最终2xx返回代码结束并stdout获取正文时发生,并且任何错误都将显示到 stderr。

请注意,curl 文档可能会让您有点困惑,因为它提到 --fail 可能会成功处理某些 401 代码。基于不正确的测试,至少在与 --show-error 同时使用时不会。

到目前为止,我无法找到任何情况,当 curl 不是 http-succeds 与这些选项时会返回成功。

  • 这与 Ricardo Souza 的答案基本相同吗? (5认同)