最可靠方法是用curl -o /dev/null -s -w "%{http_code}" http://localhost:8080/health获取状态码,-s关闭进度条,-w仅输出状态码,漏掉任一参数会导致返回000或冗余日志。

怎么用curl检查网页HTTP状态码并判断异常
直接用 curl -o /dev/null -s -w "%{http_code}" http://localhost:8080/health 获取状态码最可靠。-o /dev/null 避免输出页面内容,-s 关闭进度条,-w "%{http_code}" 只输出状态码数字。
常见错误是漏掉 -s 或 -w,导致返回一堆 curl 日志或 000(说明请求根本没发出去,比如域名解析失败、端口不通)。
注意:如果目标服务启用了重定向(301/302),默认会跟随跳转,最终返回跳转后的状态码。需要加 -L 才能生效;若想禁止跳转、只看原始响应,必须显式加 -f(失败时返回非零退出码)和 -I(只取 header),再配合 grep 提取 HTTP/ 行。
如何写一个带超时和重试的健康检查逻辑
单次 curl 不足以判断服务是否真挂了——网络抖动、瞬时超载都可能造成误判。必须加超时和有限重试。
推荐结构:
for i in {1..3}; do
code=$(curl -o /dev/null -s -w "%{http_code}" --max-time 5 http://localhost:8080/health)
if [ "$code" = "200" ]; then
exit 0
fi
sleep 2
done
关键点:
-
--max-time 5防止卡死(不加的话,DNS 超时可能长达 30 秒) - 重试最多 3 次,每次间隔 2 秒,避免雪崩式重试
- 不要用
until或无限循环,否则服务假死时脚本自身会卡住 - 检查
$code必须用=(不是==),在 POSIX shell 中后者不可移植
重启服务前为什么要先确认进程确实存活
直接执行 systemctl restart myapp 风险很高:如果服务根本没起来(比如 systemd 启动失败后自动退出),重启命令会卡住或静默失败,监控脚本就失去意义。
安全做法是分两步验证:
- 用
systemctl is-active --quiet myapp确认当前处于 active 状态(否则不重启) - 重启后,等 3 秒,再跑一遍健康检查,确保新实例真的返回 200
- 如果重启后仍不健康,不要连续重试——记录日志并退出,防止反复拉起崩溃进程
示例片段:
if systemctl is-active --quiet myapp; then
systemctl restart myapp
sleep 3
if ! check_health; then
logger -t healthcheck "Restart failed for myapp"
exit 1
fi
fi
为什么不能把监控脚本丢进 crontab 就完事
crontab 缺少环境变量(尤其是 $PATH 和 systemd 权限),常导致 systemctl 报 “Failed to connect to bus” 或找不到 curl。
解决办法只有两个:
- 在脚本开头显式声明 PATH:
PATH=/usr/local/bin:/usr/bin:/bin - 用
systemctl --user的话,cron 必须以对应用户启动,且 session bus 已就绪;生产环境更建议用 root 用户 +systemctl(需在 cron 中加export XDG_RUNTIME_DIR="/run/user/0") - 绝对路径不能省:
/usr/bin/curl、/bin/systemctl,避免依赖 shell 查找
另外,别用 @reboot 启动监控脚本——系统刚起来时 network.target 可能未就绪,curl 会连不上。改用 systemd timer 更可控。











