JavaScript实现SOAP调用返回HTML但SOAP UI返回XML如何解决
问题描述
我为GET请求实现了一个基础的SOAP调用,为此我在SOAP UI中测试了入口点以获取所需信息,该代码在使用服务层的Angular 12组件中实现。
目前我已经准备好了调用所需的信封和响应示例,现在我尝试在JavaScript中实现该功能,我在服务层中设置了XMLHttpRequest,注意:我还使用了代理,这就是我调用地址为localhost:4300的原因。
服务层实现代码:
public soapCall() { var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://localhost:4300/WS/GetCategories.fsp', true); // build SOAP request var sr = '<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' + 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ' + 'xmlns:bran="http://www.bottomline.com/soap/branch/"> ' + '<soapenv:Header/> ' + '<soapenv:Body> ' + '<bran:CallBranch soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> ' + '</soapenv:Body> ' + '</soapenv:Envelope>'; // Send the request xhr.setRequestHeader('Content-Type', 'text/xml'); xhr.setRequestHeader('Access-Control-Allow-Origin','*'); xhr.setRequestHeader('Access-Control-Allow-Methods','*'); xhr.setRequestHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); let map = new Map(); map.set("xhr", xhr); map.set("sr", sr); return map; // xhr.send(sr); }
最后我在组件中发起调用:
soapCall() { let map = this.soapService.anotherCall() let xhr = map.get('xhr'); let str = map.get('sr') xhr.send(str); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status == 200) { alert(xhr.responseText); // alert('done. use firebug/console to see network response'); } } } console.log(str) }
输出结果不符合我的预期,它返回了嵌套XML的HTML内容,实际上我在使用传统REST调用时也遇到了相同的问题。
解决方案
核心问题
SOAP 1.1协议要求必须使用POST方法提交请求体,你使用GET方法发送XML的行为不符合规范,服务端会将请求识别为普通资源访问,直接返回接口描述页面而非SOAP响应。
需要调整的点
- 将
XMLHttpRequest.open的请求方法从GET修改为POST - 移除所有
Access-Control-Allow-*开头的请求头,这些头属于服务端响应头,客户端请求添加无任何作用,反而可能触发跨域预检错误 - 按需添加
SOAPAction请求头,部分SOAP服务要求该字段,具体值可以从SOAP UI的请求头配置中复制 - 调整回调绑定顺序,先绑定
onreadystatechange回调再调用send方法,避免响应返回过快导致回调未绑定丢失数据 - 优先使用
xhr.responseXML获取XML格式响应,避免HTML嵌套干扰后续解析
修正后代码
服务层代码
public soapCall() { const xhr = new XMLHttpRequest(); // 修改为POST请求 xhr.open('POST', 'http://localhost:4300/WS/GetCategories.fsp', true); const sr = `<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:bran="http://www.bottomline.com/soap/branch/"> <soapenv:Header/> <soapenv:Body> <bran:CallBranch soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </soapenv:Body> </soapenv:Envelope>`; // 仅保留必要请求头 xhr.setRequestHeader('Content-Type', 'text/xml;charset=utf-8'); // 若服务要求SOAPAction则取消注释,值从SOAP UI中获取 // xhr.setRequestHeader('SOAPAction', ''); const map = new Map(); map.set("xhr", xhr); map.set("sr", sr); return map; }
组件调用代码
soapCall() { const map = this.soapService.soapCall(); const xhr = map.get('xhr'); const str = map.get('sr'); // 先绑定回调再发送请求 xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { // 直接获取XML响应,避免HTML干扰 const responseXml = xhr.responseXML; console.log('SOAP响应内容', responseXml); // 如需解析XML可使用DOMParser提取目标字段 } else { console.error('请求失败', xhr.status, xhr.statusText); } } } xhr.send(str); console.log('SOAP请求体', str); }
内容的提问来源于stack exchange,提问作者davidvera
相关产品推荐
相关产品推荐

