CentOS6下PHP5.3调用HTTPS SOAP服务报HTTP请求错误求助
我在老环境里踩过类似的坑,CentOS 6搭配PHP 5.3的组合确实容易出现这种看似矛盾的问题——明明写了HTTPS URL,实际却发了纯HTTP请求到443端口。结合你给出的数据包和代码,下面是几个大概率能解决问题的排查方向:
1. 先确认PHP的SSL扩展是否正常启用
PHP 5.3如果没装openssl扩展,哪怕你代码里写了https://,SoapClient底层也没法处理SSL握手,最终会 fallback 到纯HTTP请求。
执行这条命令检查扩展状态:
php -m | grep openssl
如果没有任何输出,说明openssl扩展未安装,CentOS 6下可以用yum快速安装:
yum install php-openssl
安装完成后记得重启Apache或PHP-FPM服务。
2. 修正SoapClient参数,强制指定HTTPS请求地址
PHP 5.3的SoapClient有个坑:解析完WSDL后,会优先使用WSDL文件里定义的服务地址,而不是你初始化时传入的URL。如果WSDL里的soap:address是HTTP协议,后续请求就会直接发纯HTTP到443端口。
另外老版本PHP对stream_context的HTTPS配置支持有限,建议调整配置并手动指定location参数:
$url = "https://127.0.0.1/soap/wsdl?wsdl"; $context = stream_context_create(array( 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true, // CentOS6的openssl版本较低,指定兼容的TLS版本 'ssl_method' => SOAP_SSL_METHOD_TLS, ) )); $client = new SoapClient($url, array( 'stream_context' => $context, 'trace' => 1, 'exceptions' => true, 'soap_version' => SOAP_1_2, // 手动指定HTTPS服务地址,覆盖WSDL中的默认地址 'location' => 'https://127.0.0.1/index.php/soap/wsdl' )); try{ $response = $client->__soapCall("test",array()); echo $response; }catch (SoapFault $f){ var_dump($f->getMessage()); var_dump($client->__getLastRequest()); var_dump($client->__getLastResponse()); }
3. 检查WSDL文件里的服务地址
先把WSDL文件下载到本地,看看里面的服务地址是不是HTTP协议:
curl https://127.0.0.1/soap/wsdl?wsdl -o local.wsdl
打开local.wsdl搜索<soap:address location="..."/>,如果里面的地址是http://127.0.0.1/...,这就是问题根源——SoapClient会无视你初始化时的HTTPS URL,直接用WSDL里的地址发请求。
这种情况要么修改WSDL文件里的地址为HTTPS,要么就像上面代码那样用location参数强制覆盖。
4. 强制SoapClient使用curl发送请求(如果有curl扩展)
PHP 5.3的SoapClient有两种实现:基于libxml流或curl。如果你的PHP安装了curl扩展,试试用curl的context配置,可能比SSL流更稳定:
$context = stream_context_create(array( 'curl' => array( CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1, ) ));
把这个context传给SoapClient即可。
最后验证
修改配置后再抓包确认:正常的HTTPS请求会先完成SSL握手,然后才发送HTTP请求内容,不会直接发纯HTTP到443端口。
内容的提问来源于stack exchange,提问作者钟苏杭

