最简单的SOAP示例

264

如何使用Javascript编写最简单的SOAP示例?

为了尽可能有用,答案应该:

  • 具有功能性(也就是实际上能工作)
  • 发送至少一个参数,可以在代码中的其他位置设置
  • 处理至少一个结果值,可以在代码的其他位置读取
  • 与大多数现代浏览器版本兼容
  • 尽可能清晰简短,不使用外部库

5
简单明了可能与不使用外部库相冲突。你真的想自己编写WSDL -> JS类转换器吗? - mikemaccana
19
我有一个问题:如果我以第一人称看到这个问题,我会预计它会被踩评,并附带评论"展示一些代码,这不是“雇佣程序员”"。没有个人攻击,Thomas :) 但我不明白社区是如何决定什么是好的和坏的。 - 最白目
4
没问题。我想这个问题的重点在于使用JavaScript编写SOAP客户端的方式有很多种。其中很多方式都很丑陋,所以我希望能得到一些保持代码整洁的建议。 - Thomas Bratt
@dan 这是因为1.这个问题比较老,仍然有很多基础问题需要解答,而传统上这些问题会得到很多赞同;2.它描述的是一个相对简单的问题,所以可能会吸引新用户,他们可能会根据“嘿,我也想知道!”的原则投票,而不是“嘿,这个问题表现出了研究的努力,它是有用和清晰的!”。由于我认为这个问题缺乏这一点,所以我给它投了反对票。没有任何个人恩怨 :D - phil294
1
@ThomasBratt 我可能会在元上继续这个话题,但是那些类型的问题值得一试。这是一个理想的问题,适合一个良好的参考库或知识库。但也许被接受的答案也应该因为额外的工作而获得激励?仍然没有比SO更受欢迎的东西,那么其他地方呢?即使SO尝试并玩弄建立文档网站的想法 - 但失败了。没有什么可以取代SO... - YoYo
13个回答

225

这是我能够创建的最简单的JavaScript SOAP客户端。

<html>
<head>
    <title>SOAP JavaScript Client Test</title>
    <script type="text/javascript">
        function soap() {
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open('POST', 'https://somesoapurl.com/', true);

            // build SOAP request
            var sr =
                '<?xml version="1.0" encoding="utf-8"?>' +
                '<soapenv:Envelope ' + 
                    'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
                    'xmlns:api="http://127.0.0.1/Integrics/Enswitch/API" ' +
                    'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
                    'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">' +
                    '<soapenv:Body>' +
                        '<api:some_api_call soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' +
                            '<username xsi:type="xsd:string">login_username</username>' +
                            '<password xsi:type="xsd:string">password</password>' +
                        '</api:some_api_call>' +
                    '</soapenv:Body>' +
                '</soapenv:Envelope>';

            xmlhttp.onreadystatechange = function () {
                if (xmlhttp.readyState == 4) {
                    if (xmlhttp.status == 200) {
                        alert(xmlhttp.responseText);
                        // alert('done. use firebug/console to see network response');
                    }
                }
            }
            // Send the POST request
            xmlhttp.setRequestHeader('Content-Type', 'text/xml');
            xmlhttp.send(sr);
            // send request
            // ...
        }
    </script>
</head>
<body>
    <form name="Demo" action="" method="post">
        <div>
            <input type="button" value="Soap" onclick="soap();" />
        </div>
    </form>
</body>
</html> <!-- typo -->

4
发送一个 soapenv:Header 怎么样?我试图将我的头标签构建到 sr 变量中,但是服务器接收到一个空的 soapenv:Header。 - Boiler Bill
1
这对我有用!(在将SOAP服务URL替换为真实URL并关闭浏览器上的跨域限制后,就像@Prestaul所暗示的那样) - Niko Bellic
我正在使用Nativescript开发跨平台应用程序,适用于Android/iOS。我想使用SOAP Web服务,请指导我如何操作。我已经使用了上述代码进行SOAP请求,并且我希望得到SOAP响应格式,如何处理响应。请查看我的问题 - https://dev59.com/a5fga4cB1Zd3GeqPCeb9 - Onkar Nene
3
最近我不得不使用这个来支持传统代码。遇到了一个缺少头文件的问题,导致“EndpointDispatcher”的“ContractFilter不匹配”。在 xmlhttp.send(sr) 之前添加 xmlhttp.setRequestHeader('SOAPAction', 'http://myurl.com/action'); 就解决了该问题。 - Rickchip
2
@Rickchip,在这里有一种更通用的解决方法:可以在需要时调用setRequestHeader()来添加头信息。 - Timo
在这种情况下,WSDL会是什么? - Miguel

81

浏览器处理XMLHttpRequest的方式有很多怪癖,这段JS代码可以在所有浏览器上运行:
https://github.com/ilinsky/xmlhttprequest

这段JS代码可以将XML转换为易于使用的JavaScript对象:
http://www.terracoder.com/index.php/xml-objectifier

以上JS代码可在页面中包含,以满足您不需要外部库的要求。

var symbol = "MSFT"; 
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "http://www.webservicex.net/stockquote.asmx?op=GetQuote",true);
xmlhttp.onreadystatechange=function() {
 if (xmlhttp.readyState == 4) {
  alert(xmlhttp.responseText);
  // http://www.terracoder.com convert XML to JSON 
  var json = XMLObjectifier.xmlToJSON(xmlhttp.responseXML);
  var result = json.Body[0].GetQuoteResponse[0].GetQuoteResult[0].Text;
  // Result text is escaped XML string, convert string to XML object then convert to JSON object
  json = XMLObjectifier.xmlToJSON(XMLObjectifier.textToXML(result));
  alert(symbol + ' Stock Quote: $' + json.Stock[0].Last[0].Text); 
 }
}
xmlhttp.setRequestHeader("SOAPAction", "http://www.webserviceX.NET/GetQuote");
xmlhttp.setRequestHeader("Content-Type", "text/xml");
var xml = '<?xml version="1.0" encoding="utf-8"?>' +
 '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
                'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
                'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' + 
   '<soap:Body> ' +
     '<GetQuote xmlns="http://www.webserviceX.NET/"> ' +
       '<symbol>' + symbol + '</symbol> ' +
     '</GetQuote> ' +
   '</soap:Body> ' +
 '</soap:Envelope>';
xmlhttp.send(xml);
// ...Include Google and Terracoder JS code here...

另外还有两个选项:


如果我想传递多个信封,我该怎么办? - Ajay Patel
我正在使用上述代码,但是xmlhttp.responseText始终为null。你能提供一些链接来解决这个错误吗? - user969275
当Google Code被移除时的链接:https://github.com/ilinsky/xmlhttprequest - ToastyMallows

50

除非网络服务与您的页面在同一域中,否则无法使用纯JavaScript完成此操作。 在2008年和IE<10中,如果服务不在与您的页面相同的域中,则无法使用纯javascript完成此操作。

如果网络服务位于另一个域中[并且您需要支持IE<10],则必须在自己的域上使用代理页面来检索结果并将其返回给您。 如果您不需要旧版IE的支持,则需要为服务添加CORS支持。 无论哪种情况,您都应该使用像timyates建议的库,因为您不希望自己解析结果。

如果网络服务位于您自己的域上,请不要使用SOAP。 没有充分的理由这样做。 如果网络服务在您自己的域上,请修改它以便能够返回JSON,并避免处理所有与SOAP相关的麻烦。

简短的答案是:不要从javascript发出SOAP请求。 使用网络服务从另一个域请求数据,如果这样做,则在服务器端解析结果并以js友好的形式返回它们。


1
在那里回答没有意义... 我同意 Gizmo 的三点观点。XML 冗长而且使用js处理起来很有挑战性,而 JSON 简洁且本地化。 - Prestaul
10
如果客户端支持“跨域资源共享”(Cross-Origin Resource Sharing),现在可以使用纯JavaScript(大部分)实现,但不是所有客户端都支持。希望在未来的三到四年内,“跨域资源共享”能够得到普及。 - Constantin
3
如果您愿意仅支持更新的浏览器并且可以控制服务器并在那里添加CORS支持,则CORS将允许它。话虽如此,我仍认为SOAP调用应该仅在服务器之间进行,客户端应该使用更适合JS的东西,比如JSON。 - Prestaul
1
@NikoBellic 一个基于浏览器的客户端可能会使用XMLHttpRequest,通常是通过像jquery这样的库。而Node客户端则会使用其他东西。大多数Web服务都使用REST作为设计其API的指南,但也有许多好的模式。关键在于请求/响应体是JSON,因为JavaScript客户端(浏览器/Node/任何地方)本地理解JSON。 - Prestaul
2
这并没有回答问题。如果你的域名上有一个第三方应用程序,而你无法“修改以返回JSON”,那么该怎么办呢? - ToastyMallows
显示剩余3条评论

16

您可以使用jquery.soap插件来为您完成工作。

此脚本使用$.ajax发送SOAPEnvelope。它可以将XML DOM、XML字符串或JSON作为输入,并且响应也可以作为XML DOM、XML字符串或JSON返回。

来自该网站的示例用法:

$.soap({
    url: 'http://my.server.com/soapservices/',
    method: 'helloWorld',

    data: {
        name: 'Remy Blom',
        msg: 'Hi!'
    },

    success: function (soapResponse) {
        // do stuff with soapResponse
        // if you want to have the response as JSON use soapResponse.toJSON();
        // or soapResponse.toString() to get XML string
        // or soapResponse.toXML() to get XML DOM
    },
    error: function (SOAPResponse) {
        // show error
    }
});

9

有人尝试过这个吗?https://github.com/doedje/jquery.soap

看起来非常容易实现。

示例:

$.soap({
url: 'http://my.server.com/soapservices/',
method: 'helloWorld',

data: {
    name: 'Remy Blom',
    msg: 'Hi!'
},

success: function (soapResponse) {
    // do stuff with soapResponse
    // if you want to have the response as JSON use soapResponse.toJSON();
    // or soapResponse.toString() to get XML string
    // or soapResponse.toXML() to get XML DOM
},
error: function (SOAPResponse) {
    // show error
}
});

会导致
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <helloWorld>
        <name>Remy Blom</name>
        <msg>Hi!</msg>
    </helloWorld>
  </soap:Body>
</soap:Envelope>

7

Thomas:

JSON 更适用于前端使用,因为我们可以轻松查找。因此您无需处理 XML。如果不使用库,SOAP 将是个麻烦。有人提到了 SOAPClient,这是一个很好的库,我们在项目中开始使用它。然而,它有一些限制,我们不得不重新编写大量代码。它已经发布为 SOAPjs 并支持向服务器传递复杂对象,并包括一些示例代理代码以从其他域消费服务。


2
“JSON 更适合于前端使用,因为它是 JavaScript。” - JSON 不是 JavaScript。(它只是看起来像 JavaScript。) - nnnnnn
2
JSON(JavaScript对象表示法)字面上的意思是“JavaScript Object Notation”,虽然我同意JSON是一种规范而不是一种语言,因此明显“不是JavaScript”,但你必须承认它的命名方式很容易让人们感到困惑。 - P. Roe
1
JSON被前端使用是因为它是JavaScript,这使得它更受欢迎。请注意,这里的链接已经失效,不要再传播错误信息。 - Martin Konecny

6
<html>
 <head>
    <title>Calling Web Service from jQuery</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $("#btnCallWebService").click(function (event) {
                var wsUrl = "http://abc.com/services/soap/server1.php";
                var soapRequest ='<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body> <getQuote xmlns:impl="http://abc.com/services/soap/server1.php">  <symbol>' + $("#txtName").val() + '</symbol>   </getQuote> </soap:Body></soap:Envelope>';
                               alert(soapRequest)
                $.ajax({
                    type: "POST",
                    url: wsUrl,
                    contentType: "text/xml",
                    dataType: "xml",
                    data: soapRequest,
                    success: processSuccess,
                    error: processError
                });

            });
        });

        function processSuccess(data, status, req) { alert('success');
            if (status == "success")
                $("#response").text($(req.responseXML).find("Result").text());

                alert(req.responseXML);
        }

        function processError(data, status, req) {
        alert('err'+data.state);
            //alert(req.responseText + " " + status);
        } 

    </script>
</head>
<body>
    <h3>
        Calling Web Services with jQuery/AJAX
    </h3>
    Enter your name:
    <input id="txtName" type="text" />
    <input id="btnCallWebService" value="Call web service" type="button" />
    <div id="response" ></div>
</body>
</html>

这是一份最佳JavaScript与SOAP教程,包含示例。 http://www.codeproject.com/Articles/12816/JavaScript-SOAP-Client

4

使用JavaScript轻松消费SOAP Web服务 -> 清单B

function fncAddTwoIntegers(a, b)
{
    varoXmlHttp = new XMLHttpRequest();
    oXmlHttp.open("POST",
 "http://localhost/Develop.NET/Home.Develop.WebServices/SimpleService.asmx'",
 false);
    oXmlHttp.setRequestHeader("Content-Type", "text/xml");
    oXmlHttp.setRequestHeader("SOAPAction", "http://tempuri.org/AddTwoIntegers");
    oXmlHttp.send(" \
<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' \
xmlns:xsd='http://www.w3.org/2001/XMLSchema' \
 xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'> \
  <soap:Body> \
    <AddTwoIntegers xmlns='http://tempuri.org/'> \
      <IntegerOne>" + a + "</IntegerOne> \
      <IntegerTwo>" + b + "</IntegerTwo> \
    </AddTwoIntegers> \
  </soap:Body> \
</soap:Envelope> \
");
    return oXmlHttp.responseXML.selectSingleNode("//AddTwoIntegersResult").text;
}

这可能不能完全满足您的需求,但它是实际回答您问题的一个开始。(我将XMLHttpRequest()替换为ActiveXObject("MSXML2.XMLHTTP"))。


3

这里有一些很好的例子(以及一个现成的JavaScript SOAP客户端!): http://plugins.jquery.com/soap/

请查看自述文件,并注意同源浏览器限制。


2
问题是“使用Javascript的最简单的SOAP示例是什么?”
这个答案是在Node.js环境中的一个示例,而不是在浏览器中。(我们将脚本命名为soap-node.js)我们将使用来自Europe PMC的公共SOAP Web服务作为示例,以获取一篇文章的参考文献列表。
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const DOMParser = require('xmldom').DOMParser;

function parseXml(text) {
    let parser = new DOMParser();
    let xmlDoc = parser.parseFromString(text, "text/xml");
    Array.from(xmlDoc.getElementsByTagName("reference")).forEach(function (item) {
        console.log('Title: ', item.childNodes[3].childNodes[0].nodeValue);
    });

}

function soapRequest(url, payload) {
    let xmlhttp = new XMLHttpRequest();
    xmlhttp.open('POST', url, true);

    // build SOAP request
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4) {
            if (xmlhttp.status == 200) {
                parseXml(xmlhttp.responseText);
            }
        }
    }

    // Send the POST request
    xmlhttp.setRequestHeader('Content-Type', 'text/xml');
    xmlhttp.send(payload);
}

soapRequest('https://www.ebi.ac.uk/europepmc/webservices/soap', 
    `<?xml version="1.0" encoding="UTF-8"?>
    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header />
    <S:Body>
        <ns4:getReferences xmlns:ns4="http://webservice.cdb.ebi.ac.uk/"
            xmlns:ns2="http://www.scholix.org"
            xmlns:ns3="https://www.europepmc.org/data">
            <id>C7886</id>
            <source>CTX</source>
            <offSet>0</offSet>
            <pageSize>25</pageSize>
            <email>ukpmc-phase3-wp2b---do-not-reply@europepmc.org</email>
        </ns4:getReferences>
    </S:Body>
    </S:Envelope>`);

在运行代码之前,您需要安装两个软件包:
npm install xmlhttprequest
npm install xmldom

现在你可以运行代码了:
node soap-node.js

"你会看到以下输出:"
Title:  Perspective: Sustaining the big-data ecosystem.
Title:  Making proteomics data accessible and reusable: current state of proteomics databases and repositories.
Title:  ProteomeXchange provides globally coordinated proteomics data submission and dissemination.
Title:  Toward effective software solutions for big biology.
Title:  The NIH Big Data to Knowledge (BD2K) initiative.
Title:  Database resources of the National Center for Biotechnology Information.
Title:  Europe PMC: a full-text literature database for the life sciences and platform for innovation.
Title:  Bio-ontologies-fast and furious.
Title:  BioPortal: ontologies and integrated data resources at the click of a mouse.
Title:  PubMed related articles: a probabilistic topic-based model for content similarity.
Title:  High-Impact Articles-Citations, Downloads, and Altmetric Score.

3
这对我有用,但我个人更喜欢使用axios。让xlms = "<?xml version="1.0" encoding="UTF-8"?> <S:Envelope xmlns:S="" rel = "nofollow noreferrer">http://schemas.xmlsoap.org/soap/envelope/"> <S:Header /> <S:Body> ... </S:Body> </S:Envelope>"使用 axios 发送 POST 请求到 'https://www.ebi.ac.uk/europepmc/webservices/soap',发送的内容为 xmls,并且设置请求头为 'Content-Type': 'text/xml'。 如果成功,打印响应结果;如果失败,打印错误。 - otoloye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接