如何在NuSOAP客户端启用WS-RM 1.2?代码报错及版本兼容咨询
让我们一步步解决你的问题,先从最直观的HTTP 415错误入手,再聊聊WS-RM支持和PHP版本兼容性的事儿。
1. 先搞定HTTP 415错误(最紧急的问题)
你看到的错误提示Unsupported HTTP response status 415 Cannot process the message because the content type 'text/xml; charset=UTF-8' was not the expected type 'application/soap+xml; charset=utf-8'已经把问题说得很清楚了:
你发送的请求用了SOAP 1.1标准的
text/xml内容类型,但目标API要求的是SOAP 1.2的application/soap+xml格式。
虽然你初始化nusoap_client时指定了soap_version => SOAP_1_2,但NuSOAP有时候不会自动设置对应的HTTP头。你需要手动强制添加这个头:
在调用$client->send()之前,加上这行代码:
// 强制设置SOAP 1.2要求的Content-Type头 $client->setHTTPHeader('Content-Type', 'application/soap+xml; charset=utf-8');
另外,SOAP 1.2规范里,SOAPAction头是可选的,有些API甚至会因为这个头存在而报错。你可以尝试把$soapaction参数改成空字符串:
$xmlobjs = $client->send($credentials, '');
2. NuSOAP对WS-RM 1.2的支持情况
很遗憾地说,NuSOAP这个老库原生根本不支持WS-ReliableMessaging(WS-RM)1.2版本。你尝试的array('reliable' => 1.2 , 'useWSA' => TRUE)参数完全无效——NuSOAP的源代码和官方文档里都没有这个配置项,所以这个设置不会有任何作用。
如果你的目标API强制要求使用WS-RM 1.2,那NuSOAP可能不是合适的选择:
- 如果你能升级PHP版本,推荐用
phpro/soap-client这类现代SOAP库,对WS规范的支持更完善 - 要是必须用PHP 5.4,那你得自己手动编写WS-RM 1.2的SOAP头XML,手动添加到请求里——这需要你对WS-RM规范有一定了解
- 也可以试试PHP原生的
SoapClient扩展(PHP 5.4支持),但它对WS-RM的支持也有限,可能需要自定义处理头信息
3. PHP 5.4.42的兼容性问题
NuSOAP的0.9.x稳定版是支持PHP 5.4的,所以你的代码在这个环境下是可以运行的——前提是解决了前面的Content-Type和WS-RM相关问题。
不过必须提醒你:PHP 5.4已经停止安全更新很多年了,存在大量未修复的安全漏洞,强烈建议你尽快升级到PHP 7.4及以上版本。
额外的代码优化建议
考虑到你对PHP和SOAP不太熟悉,给你几个实用的优化点:
- 不要手动拼SOAP XML:NuSOAP可以帮你自动生成请求XML,避免手动拼接时出现的语法错误。比如你可以用
$client->call()方法直接调用API方法,传递参数数组就行 - 完善错误处理:除了检查
getError(),还要检查$client->fault来判断是否返回了SOAP Fault - 敏感信息不要硬编码:把AgentCode、密码这类敏感信息放到配置文件或环境变量里,不要直接写在代码里
这里给你一个优化后的示例代码(自动生成SOAP请求):
try { include_once 'WebServiceSOAP/lib/nusoap.php'; $api_link = 'https://www.my-api.com/MYAPI.svc/SSL?wsdl'; $acode = '###'; $uname = '###'; $ttype = '###'; $ccode = '###'; $hpass = '###'; // 初始化SOAP客户端 $client = new nusoap_client($api_link, array( 'cache_wsdl' => WSDL_CACHE_NONE, 'soap_version' => SOAP_1_2 )); $client->soap_defencoding = 'UTF-8'; // 设置SOAP 1.2要求的Content-Type $client->setHTTPHeader('Content-Type', 'application/soap+xml; charset=utf-8'); // 准备请求参数 $requestParams = array( 'credentials' => array( 'AgentCode' => $acode, 'HashedPassword' => $hpass, 'Username' => $uname ), 'payincurcode' => $ccode, 'transferType' => $ttype ); // 调用API方法 $response = $client->call('GetLocalRates', $requestParams); // 检查SOAP Fault if ($client->fault) { echo '<h2>SOAP Fault 错误</h2><pre>' . print_r($response, true) . '</pre>'; exit; } // 检查客户端错误 $clientError = $client->getError(); if ($clientError) { echo '<h2>客户端请求错误</h2><pre>' . $clientError . '</pre>'; exit; } // 输出响应结果 print_r($response); } catch(Exception $e) { echo '异常错误:' . $e->getMessage(); }
内容的提问来源于stack exchange,提问作者Ujith Nimantha

