PHP项目调用外部API时,常见现象是终端里的测试脚本正常,放到Nginx加PHP-FPM后却超时。原因通常不是代码突然变了,而是CLI与FPM使用了不同用户、环境变量、证书文件和网络权限。若项目又通过Guzzle封装cURL,配置层级会更多。
一、先确认PHP实际使用哪个网络实现
直接调用cURL扩展时,代理由CURLOPT_PROXY等选项控制;Guzzle则通过请求选项和底层Handler发送。部分项目还可能使用流封装器或框架自带HTTP客户端。排查前先确认调用栈,不要只看Composer里安装了什么包。
二、cURL最小代理配置
$ch = curl_init('https://api.example.com/health');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_PROXY => 'http://proxy.example:8080',
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 30,
]);
$result = curl_exec($ch);如需认证,可使用专门的代理认证选项,避免把账号密码拼进日志会打印的URL。SOCKS代理还要明确代理类型;是否由代理解析域名,应按cURL版本和选项验证。
三、访问HTTPS为什么仍写HTTP代理
http://proxy.example:8080描述的是客户端连接代理的方式,不代表最终目标只能是HTTP。访问HTTPS目标时,常见HTTP代理会接收CONNECT请求,建立TCP隧道,之后客户端在隧道内与目标完成TLS握手。
具体过程可参考HTTPS代理CONNECT隧道原理。
四、Guzzle的proxy选项怎么理解
Guzzle可以在客户端默认配置或单次请求中设置proxy。当HTTP、HTTPS目标需要不同出口时,可按协议配置,并为内网目标设置绕过列表。项目应固定Guzzle和Handler版本,因为不同底层实现对环境变量、调试输出和代理类型的支持边界可能不同。
$client = new GuzzleHttpClient([
'proxy' => 'http://proxy.example:8080',
'connect_timeout' => 10,
'timeout' => 30,
]);五、CLI成功、PHP-FPM失败怎么查
| 差异 | 检查方法 |
|---|---|
| 运行用户 | 确认FPM池用户及文件权限 |
| 环境变量 | 从实际FPM进程读取,不依赖终端export |
| php.ini | 分别查看CLI与FPM加载路径 |
| CA文件 | 核对curl.cainfo和openssl.cafile |
| 网络策略 | 确认服务用户、容器或安全组允许出站 |
| DNS | 在相同网络命名空间中解析 |
不要为了调试直接在网页输出phpinfo()到公网,它可能泄露路径、模块和环境信息。
六、407、401和502分别看哪里
407通常说明代理要求认证;401多半是目标API认证失败;502可能是代理无法连接上游或上游响应异常。应同时记录代理状态码、目标主机和时间线,但对授权头、Cookie、代理账号和API令牌做脱敏。
七、证书错误为什么不能关闭verify
若代理仅做CONNECT,目标证书仍由PHP客户端验证;若企业环境执行受控TLS检查,客户端看到的可能是企业签发证书。无论哪种情况,都应修复CA路径、证书链、域名或系统时间。将Guzzle的verify设为false只适合极短暂的隔离诊断,不应进入正式配置。
完整排查顺序见HTTPS代理证书错误指南。
八、连接复用如何影响代理切换
常驻PHP进程、队列Worker或高性能应用服务器可能保持客户端和连接。更新环境变量或配置文件后,旧Worker不一定自动加载新值。应按部署方式平滑重启或轮换Worker,并确认在途请求结束后旧连接退出。
九、生产环境应该怎样放凭据
- 不要把代理账号写入Git仓库或Composer配置示例;
- 不要在异常页面、调试中间件和访问日志中输出完整代理URL;
- 使用权限受限的秘密配置源,并区分开发、测试和生产;
- 定期轮换凭据,更新后重建相关连接;
- 工单只提交脱敏错误和请求ID。
十、排查清单
- 确认cURL、Guzzle及底层Handler版本;
- 用最小脚本访问授权测试端点;
- 比较CLI与FPM的用户、配置和CA路径;
- 区分DNS、TCP、407、TLS与目标401;
- 验证HTTP代理、SOCKS代理和DNS解析方式;
- 重载常驻Worker后复测出口;
- 清理临时调试页面和明文凭据。
十一、结论
PHP代理故障应从实际运行环境出发。先确认请求由谁发送,再检查cURL或Guzzle选项、FPM环境、CONNECT、认证和CA信任。把命令行结果直接等同于网站进程,是这类问题中最常见的误判。






