You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CLI带证书Curl请求正常,PHP实现却返回400错误

PHP CURL请求OAuth2令牌返回400 Bad Request(CLI正常,Docker环境异常)

问题概述

  • 一套带客户端证书的OAuth2令牌获取请求,在CLI下用curl命令可正常执行并拿到令牌,但转成PHP的CURL代码后,请求始终返回400 Bad Request
  • API强制要求请求携带客户端证书,对比两者的verbose输出,发现TLS握手阶段存在明显差异,曾怀疑CURLOPT_SSLCERT和CURLOPT_SSLKEY是否与CLI的--cert、--key参数对应
  • 后续通过Wireshark抓包发现,请求序列末尾存在TCP重传差异;且在Docker环境外运行PHP代码无任何错误,因此推测问题根源在于Docker开发环境配置

原始代码对比

CLI curl命令

curl --request POST 
  --url    https://sysorgoauth2.test.XXX.TLD/oauth2/v1/sysorg/token 
  --cert   /app/keys/eid.crt.pem 
  --key    /app/keys/eid.key.pem 
  --header "Content-Type: application/x-www-form-urlencoded" 
  --verbose 
  -d "grant_type=client_credentials&client_id=<ID>&client_secret=<SECRET>&scope=<SCOPE>"

PHP CURL代码

$headers = [
  'User-Agent: curl/7.74.0 via PHP',
  'Content-Type: application/x-www-form-urlencoded',
  'Accept: */*',
];

$url = 'https://sysorgoauth2.test.XXX.TLD/oauth2/v1/sysorg/token';
$data = [
  'grant_type' => 'client_credentials',
  'client_id' => '<ID>',
  'client_secret' => '<SECRET>',
  'scope' => '<SCOPE>',
];
$body = http_build_query($data);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSLCERT, '/app/keys/eid.crt.pem');
curl_setopt($ch, CURLOPT_SSLKEY, '/app/keys/eid.key.pem');
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

// 调试输出
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
$stream = fopen('/tmp/curl_debug.txt', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $stream);

$response = curl_exec($ch);
curl_close($ch);

排查方向与修复方案

首先明确:CURLOPT_SSLCERT确实对应CLI的--cert,CURLOPT_SSLKEY对应--key,参数映射本身没有问题,问题集中在Docker环境的配置差异上,可从以下几点排查:

1. 证书文件权限检查

Docker容器内的PHP进程(通常是www-data用户)可能没有证书文件的读取权限,导致TLS握手失败。执行以下命令确认并修复权限:

# 进入Docker容器
docker exec -it <容器ID> bash
# 检查证书权限
ls -l /app/keys/eid.crt.pem /app/keys/eid.key.pem
# 若权限不足,修改权限
chmod 644 /app/keys/eid.crt.pem /app/keys/eid.key.pem
chown www-data:www-data /app/keys/eid.crt.pem /app/keys/eid.key.pem

2. 对齐请求头信息

CLI和PHP的User-Agent不一致可能导致API校验失败,将PHP的User-Agent改为与CLI完全一致(可通过curl --version查看CLI的User-Agent):

$headers = [
  'User-Agent: curl/7.74.0', // 替换为你的CLI curl版本对应的UA
  'Content-Type: application/x-www-form-urlencoded',
  'Accept: */*',
];

3. 指定证书类型与CA根证书

部分环境需要明确指定证书类型,若API使用私有CA颁发的证书,还需指定CA证书路径:

// 明确指定证书类型为PEM
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
// 若需要验证私有CA,指定CA证书路径(仅生产环境建议)
curl_setopt($ch, CURLOPT_CAINFO, '/app/keys/ca.crt.pem');
// 测试阶段可临时关闭证书验证(不建议生产使用)
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

4. 捕获CURL错误信息

在PHP代码中添加错误捕获,定位具体问题:

$response = curl_exec($ch);
if(curl_errno($ch)) {
    echo 'CURL错误详情:' . curl_error($ch);
}
curl_close($ch);
fclose($stream);

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 23:05:27