使用PHP SoapClient调用WSDL List方法时返回‘looks like we got no XML document’错误
问题重现
- SOAP UI中调用List方法可正常请求,请求示例:
POST https://examplewsdl.com/mailwebservice/mtom/ HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8
Authorization: Basic [AUTH_TOKEN]
Content-Length: 298
Host: lms.example.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.5 (Java/16.0.1)<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:mail="http://www.examplewsdl.com/ems/mailwebservice">
soap:Header/
soap:Body
mail:ListRequest
mail:accountId123456789</mail:accountId>
</mail:ListRequest>
</soap:Body>
</soap:Envelope>
- 使用PHP SoapClient调用时返回错误
looks like we got no XML document,PHP代码:
<?php $wsdl = 'https://examplewsdl.com/mailwebservice/mtom/mailwebservice-mtom.wsdl'; $options = [ 'authentication' => SOAP_AUTHENTICATION_BASIC, 'login' => '...', 'password' => '...', 'soap_version' => SOAP_1_2, ]; try { $client = new SoapClient($wsdl, $options); $res = $client->List(['accountId' => '123456789']); } catch (SoapFault $e) { var_dump($e); }
- 已尝试MTOM消息编码方案但无效
解决方法
1. 开启调试模式排查实际请求差异
在SoapClient选项中开启trace和exceptions,执行请求后打印实际发送的请求头和内容,对比SOAP UI的请求,定位差异点:
$options = [ 'authentication' => SOAP_AUTHENTICATION_BASIC, 'login' => '...', 'password' => '...', 'soap_version' => SOAP_1_2, 'trace' => 1, 'exceptions' => 0, ]; $client = new SoapClient($wsdl, $options); $res = $client->List(['accountId' => '123456789']); // 打印请求头和内容 echo "Request Headers:\n" . $client->__getLastRequestHeaders() . "\n"; echo "Request Body:\n" . $client->__getLastRequest() . "\n"; echo "Response:\n" . $client->__getLastResponse() . "\n";
重点检查Content-Type是否为application/soap+xml;charset=UTF-8,请求体的XML结构、命名空间是否与SOAP UI完全一致。
2. 手动构造请求模拟SOAP UI逻辑
如果SoapClient自动生成的请求不符合服务要求,直接用CURL模拟SOAP UI的请求格式:
$url = 'https://examplewsdl.com/mailwebservice/mtom/'; $login = '...'; $password = '...'; // 完全复用SOAP UI的请求体 $soapBody = '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:mail="http://www.examplewsdl.com/ems/mailwebservice"> <soap:Header/> <soap:Body> <mail:ListRequest> <mail:accountId>123456789</mail:accountId> </mail:ListRequest> </soap:Body> </soap:Envelope>'; // 初始化CURL $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $soapBody); // 设置匹配SOAP UI的请求头 $headers = [ 'Content-Type: application/soap+xml;charset=UTF-8', 'Authorization: Basic ' . base64_encode("$login:$password"), 'Accept-Encoding: gzip,deflate', ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 执行请求并处理结果 $response = curl_exec($ch); if (curl_errno($ch)) { echo 'CURL Error: ' . curl_error($ch); } else { var_dump($response); } curl_close($ch);
3. 正确配置MTOM编码格式
如果服务强制要求MTOM编码,需构造符合MIME规范的请求内容:
$url = 'https://examplewsdl.com/mailwebservice/mtom/'; $login = '...'; $password = '...'; $soapBody = '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:mail="http://www.examplewsdl.com/ems/mailwebservice"> <soap:Header/> <soap:Body> <mail:ListRequest> <mail:accountId>123456789</mail:accountId> </mail:ListRequest> </soap:Body> </soap:Envelope>'; // 构造MTOM格式的请求体 $boundary = 'MIMEBoundary_' . uniqid(); $mtomBody = "--$boundary\r\n"; $mtomBody .= "Content-Type: application/xop+xml;charset=UTF-8;type=\"application/soap+xml\"\r\n"; $mtomBody .= "Content-Transfer-Encoding: binary\r\n"; $mtomBody .= "Content-ID: <rootpart@soapui.org>\r\n\r\n"; $mtomBody .= $soapBody . "\r\n"; $mtomBody .= "--$boundary--\r\n"; // 初始化CURL并设置MTOM相关请求头 $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $mtomBody); $headers = [ 'Content-Type: multipart/related;boundary="' . $boundary . '";type="application/soap+xml"', 'Authorization: Basic ' . base64_encode("$login:$password"), 'Accept-Encoding: gzip,deflate', ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 执行请求 $response = curl_exec($ch); if (curl_errno($ch)) { echo 'CURL Error: ' . curl_error($ch); } else { var_dump($response); } curl_close($ch);
关键注意点
- SOAP 1.2要求
Content-Type为application/soap+xml,而SOAP 1.1为text/xml,需确保请求头类型正确。 - XML命名空间、节点前缀必须与服务要求完全匹配,不能出现拼写错误。
内容的提问来源于stack exchange,提问作者Robbert

