PHP SoapClient调用返回base64压缩包的MTOM SOAP接口报错问询
报错信息:
SoapFault: Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'multipart/related; type="application/xop+xml"'. in file /app/app/Http/Middleware/MTOMSoapClient.php on line 8
报错底层原因
- 目标SOAP接口启用了MTOM(消息传输优化机制),该机制专为二进制附件传输设计,要求请求头
Content-Type必须为multipart/related; type="application/xop+xml",你当前发起的请求仍使用普通SOAP的text/xml请求头,因此被服务端拦截 - 你之前使用的自定义MTOMSoapClient未正确改写请求头构造逻辑,也没有在请求体中声明XOP支持,导致请求格式不符合服务端要求
解决方案
方案1:使用修正版自定义MTOMSoapClient
第一步:编写正确的MTOMSoapClient类
class MTOMSoapClient extends \SoapClient { public function __doRequest($request, $location, $action, $version, $one_way = 0) { // 构造MTOM请求边界标识 $boundary = "MTOMBoundry_" . md5(uniqid(time())); // 替换请求头为MTOM要求的格式 $headers = [ "Content-Type: multipart/related; type=\"application/xop+xml\"; boundary=\"$boundary\"; start=\"<rootpart@soapui.org>\"; start-info=\"text/xml\"", "SOAPAction: \"$action\"", ]; // 构造MTOM格式请求体 $body = "--$boundary\r\n"; $body .= "Content-Type: application/xop+xml; charset=UTF-8; type=\"text/xml\"\r\n"; $body .= "Content-Transfer-Encoding: 8bit\r\n"; $body .= "Content-ID: <rootpart@soapui.org>\r\n\r\n"; $body .= $request . "\r\n"; $body .= "--$boundary--"; // 使用CURL发起请求 $ch = curl_init($location); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $body); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); // 解析MTOM响应,提取XML内容 $response = preg_replace('/--.*[\r\n]+/', '', $response); $response = preg_replace('/Content-Type: [^\r\n]+[\r\n]+/', '', $response); $response = preg_replace('/Content-Transfer-Encoding: [^\r\n]+[\r\n]+/', '', $response); $response = preg_replace('/Content-ID: [^\r\n]+[\r\n]+/', '', $response); $response = trim($response); return $response; } }
第二步:调用代码示例
// 初始化客户端 $client = new MTOMSoapClient($url, array("soap_version" => SOAP_1_1,"trace" => 1)); $user_param = array ( 'DealerCode' => "1234", 'Hash' => "asjdfasjda1231231231", 'Password' => "somerandompassword", 'UserName' => "somerandomusername" ); $result = $client->__soapCall("DownloadOffer", array($user_param)); // 提取返回的base64编码zip内容,字段名根据实际接口返回调整 $zipContent = base64_decode($result->DownloadOfferResult->FileContent); // 保存到本地文件 file_put_contents('./offer.zip', $zipContent);
方案2:使用成熟组件laminas-soap(推荐)
laminas-soap原生支持MTOM处理,无需自己开发底层逻辑,使用步骤如下:
- 安装依赖
composer require laminas/laminas-soap
- 调用代码示例
use Laminas\Soap\Client; $client = new Client($url, [ 'soap_version' => SOAP_1_1, 'mtom' => true, // 直接开启MTOM支持 ]); $user_param = array ( 'DealerCode' => "1234", 'Hash' => "asjdfasjda1231231231", 'Password' => "somerandompassword", 'UserName' => "somerandomusername" ); $result = $client->DownloadOffer($user_param); // 提取附件内容保存即可
内容的提问来源于stack exchange,提问作者Susy11
相关产品推荐
相关产品推荐

