必须先检查 curl_getinfo($ch, CURLINFO_HTTP_CODE) 确认 HTTP 状态码,再处理响应;429 和 5xx 才应重试,400/401/403 等客户端错误重试无效;传图优先用 CURLFile,大图需预压缩;网络错误需通过 curl_errno 和 curl_error 统计。

看 curl_getinfo($ch, CURLINFO_HTTP_CODE) 再说话
别一看到返回空、报错或超时就去改参数或重写逻辑——先确认 HTTP 状态码。PHP 调用文生图接口(比如通义万相、即梦、阿里云 ImageGen)时,curl_getinfo($ch, CURLINFO_HTTP_CODE) 是唯一能告诉你“请求到底有没有发出去、服务端是否接收到”的依据。
常见误操作:只检查 $response 是否为空,或直接 json_decode($response) 然后报 NULL 就断定是数据问题。其实 401/403/400 响应体也可能含 JSON 错误信息,但你跳过状态码就直接解析,等于把错误响应当成功处理了。
- 必须在
curl_exec()之后、curl_close()之前调用curl_getinfo(..., CURLINFO_HTTP_CODE) - 若
curl_errno($ch)非零(如CURLE_OPERATION_TIMEDOUT),说明根本没拿到 HTTP 响应,此时CURLINFO_HTTP_CODE可能为 0,不能当作 5xx 处理 - 别用
http_response_code()反查——那是设置/获取当前 PHP 脚本的响应码,和第三方 API 返回码无关
429 和 5xx 才值得重试,其他重试纯属浪费请求
文生图接口普遍对并发和频次敏感,429 Too Many Requests 几乎是高频调用必见的状态码;500/502/503 则多因模型服务临时抖动或队列积压。这两类才适合加退避重试。
而 400(参数错)、401(密钥无效)、403(权限不足)、402(余额不足)全是客户端问题,重试多少次结果都一样,还可能触发更严限流。
立即学习“PHP免费学习笔记(深入)”;
- 重试前务必检查响应头:
Retry-After字段存在就按它给的秒数延迟;没有则用指数退避,例如第 1 次等 1s,第 2 次等 2s,第 3 次等 4s - 重试次数建议 ≤3 次,避免雪崩——尤其在批量生成场景下,全量重试会把峰值并发翻 3 倍
- 别在
try-catch里无差别捕获所有异常后重试:PDO 异常、JSON 解析失败、文件读取失败这些跟 HTTP 状态码无关,重试毫无意义
图片传参格式错是静默失败高发区
文生图接口对输入图像的编码方式极其挑剔。你以为传个 file_get_contents($path) 就行?大概率被服务端静默拒绝,返回 400 或空响应,且错误信息模糊(比如只说 "invalid input")。
典型不兼容点:原始二进制数据未加 Content-Type、Base64 缺少前缀、PNG/JPEG 混用但接口只认一种、图像尺寸超限却没压缩就上传。
- 优先用
new CURLFile($path, 'image/jpeg')(PHP ≥5.5),比base64_encode()更稳定,也避免手动拼接data:image/jpeg;base64,前缀出错 - 若必须 Base64,确保 MIME 类型与实际文件一致:
exif_imagetype($path) === IMAGETYPE_JPEG再决定用image/jpeg还是image/png - 大图(>2MB 或宽高 >2048px)务必预压缩:用
getimagesize()+ GD 库缩放,否则可能触发服务端内存保护直接 500
中间件里统计错误次数比 try-catch 更可靠
想监控文生图调用失败率?别只在业务代码里加 if ($httpCode >= 400) { log_error(); }。真实线上环境里,很多失败根本不会走到你写的逻辑里——比如 cURL 超时、DNS 解析失败、SSL 握手失败,这些连 HTTP 状态码都没有,curl_getinfo 返回 0,但你的 if 判断直接跳过了。
更糟的是,如果用了 ThinkPHP/Laravel 这类框架封装的 HTTP 客户端(如 Http::post()),它内部可能已 catch 住 cURL 错误并转成异常,你再 try-catch 一层,反而掩盖了原始错误类型。
- 真正要统计的,是最终发出的响应:在框架中间件的
handle()方法末尾读$response->getStatusCode()(Laravel)或$response->getCode()(ThinkPHP) - 区分两类计数:
error:network(cURL 错误码非 0)、error:http:429(有状态码但非 2xx) - 日志里必须记录原始 cURL 错误信息:
curl_error($ch)和curl_errno($ch),它们比 HTTP 状态码更能定位网络层问题
最易被忽略的是:状态码只是第一层信号。400 不一定代表你参数写错,也可能是服务端校验逻辑变更;503 不一定真是服务不可用,也许是上游鉴权网关返回的兜底码。得结合响应体内容、请求头、时间戳三者交叉验证,才能准确定位。



















