You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript实现SOAP调用返回HTML但SOAP UI返回XML如何解决

问题描述

我为GET请求实现了一个基础的SOAP调用,为此我在SOAP UI中测试了入口点以获取所需信息,该代码在使用服务层的Angular 12组件中实现。
SOAP UI测试截图

目前我已经准备好了调用所需的信封和响应示例,现在我尝试在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 22:45:02