最稳妥方式是用PHP cURL扩展发起POST请求监控接口,需设超时、检查HTTP状态码与业务码、验证响应体、正确设置Content-Type,并分离告警逻辑。

用 curl 发起 POST 请求做接口监控最稳妥
PHP 自带的 curl 扩展是监控 HTTP 接口最可靠的方式,比 file_get_contents + stream_context_create 更可控,也比第三方库(如 Guzzle)更轻量、无依赖。关键在于设置超时、错误码检查和响应体验证,而不是只看“有没有返回”。
-
curl_setopt($ch, CURLOPT_TIMEOUT, 5)必须设,否则 DNS 卡住或服务无响应会 hang 住整个脚本 - 一定要检查
curl_getinfo($ch, CURLINFO_HTTP_CODE),200 不代表业务成功,但非 2xx/3xx 通常要告警 - 用
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true)确保能拿到响应体做 JSON 解析或关键字匹配 - 别忽略
curl_error($ch)—— 连接拒绝、SSL 验证失败、域名解析失败都会进这里,这类错误比 HTTP 状态码更早暴露问题
POST 数据格式错会导致 400 或空响应
后端接口对 Content-Type 敏感,发错格式基本等于白发。常见组合有三种,必须和服务端约定一致:
- 表单提交:
curl_setopt($ch, CURLOPT_POSTFIELDS, 'a=1&b=2')+curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']) - JSON 提交:
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['a' => 1, 'b' => 2]))+curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']) - 原始字符串(如 XML):
curl_setopt($ch, CURLOPT_POSTFIELDS, '+ 对应的1 ')Content-Type
漏掉 Content-Type 头或类型不匹配,Nginx 可能直接返回 400,Laravel/Lumen 会解析失败返回空数组或报错,而你的监控脚本可能只判断了“有响应”,就误判为正常。
告警触发不能只靠 HTTP 状态码
一个接口返回 200,但实际返回 {"code":500,"msg":"DB connection failed"},这就是典型“假成功”。监控逻辑里必须加一层业务校验:
立即学习“PHP免费学习笔记(深入)”;
- 用
json_decode($response, true)解析响应,检查isset($data['code']) && $data['code'] === 0(按你接口规范调整) - 若接口不返回标准结构,可用
strpos($response, 'success') !== false做关键词匹配(注意避免误命中日志或注释) - 对支付、订单类接口,建议额外 GET 一个关联资源(比如刚创建的订单 ID),双重验证写入是否生效
- 把耗时也纳入阈值:如果正常 200ms,突然涨到 2s,即使返回 200 也要触发慢请求告警
定时执行和告警通道要分离
别把发邮件/钉钉/企微的逻辑和请求逻辑写在一起。一旦告警通道出问题(比如 SMTP 拒绝连接),整个监控就卡死或误报。推荐结构:
if ($httpCode !== 200 || $bizCode !== 0 || $elapsedMs > 1500) {
file_put_contents('/tmp/api_monitor_fail.log', date('c') . " $url $httpCode $bizCode $elapsedMs\n", FILE_APPEND);
}
再单独起一个定时任务(如每分钟)扫描这个日志文件,聚合最近 3 分钟失败次数,满足条件才调用 sendAlert()。这样请求层干净,告警层可重试、可限流、可记录发送结果。
真正难的不是发一次请求,而是让这个脚本在凌晨三点、在 PHP-FPM worker 重启后、在磁盘满时,依然稳定吐出准确的故障信号 —— 所有临时文件路径要绝对、所有外部依赖要降级兜底、所有超时要硬性截断。











