Francesco Mantovani
Francesco Mantovani

Reputation: 12327

Post a SOAP request in HTML and get response

I'm using WCFStorm in order to debug a very simple SOAP endpoint:

http://www.dneonline.com/calculator.asmx?WSDL

such endpoint can be used in order to request the 4 basic arithmetic calculations and retrieve a response: here in the example I'm requesting the numbers 3 and 5 and I receive as response 8, all good!

enter image description here

I now want to create an HTML page that can do the same without using WCFStorm. Here is my code:

<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://www.dneonline.com/calculator.asmx?WSDL";
                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://www.dneonline.com/calculator.asmx?WSDL">  <intA>' + $("#intA").val() + '</intA> <intB>' + $("#intB").val() + '</intB>  </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("Int32").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 the numbers:
    <input id="intA" type="string" />
    <input id="intB" type="string" />
    <input id="btnCallWebService" value="Call web service" type="button" />
    <div id="response"></div>
</body>

</html>

But unfortunately I can only receive an: errundefined. Where am I wrong?

Upvotes: 0

Views: 6155

Answers (3)

Francesco Mantovani
Francesco Mantovani

Reputation: 12327

Sally CJ made a great reply on this post, I believe deserves to be the one who gave the right response. I learned so many things about the CORS.

However I have to mention that there is a way to archive the result with a simple HTML file:

Calling WebService Using AJAX jQuery With SOAP

Upvotes: 0

Sally CJ
Sally CJ

Reputation: 15620

Where am I wrong?

  1. The request payload/data is not properly formatted:

    For SOAP 1.1: (request and response format are in 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>
        <Add xmlns="http://tempuri.org/">
          <intA>int</intA>
          <intB>int</intB>
        </Add>
      </soap:Body>
    </soap:Envelope>
    

    For SOAP 1.2: (request and response format are in SOAP + XML)

    <?xml version="1.0" encoding="utf-8"?>
    <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
      <soap12:Body>
        <Add xmlns="http://tempuri.org/">
          <intA>int</intA>
          <intB>int</intB>
        </Add>
      </soap12:Body>
    </soap12:Envelope>
    

    Refer to the calculator web service docs for details.

  2. And as pointed in my original answer, which is a very important thing to be considered: The calculator web service endpoint (http://www.dneonline.com/calculator.asmx?WSDL) does not have the proper CORS header (Access-Control-Allow-Origin) which is required when making CORS requests — excerpt from MDN's article about Cross-Origin Resource Sharing (CORS):

    A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) than its own origin.

    An example of a cross-origin request: The frontend JavaScript code for a web application served from http://domain-a.com uses XMLHttpRequest to make a request for http://api.domain-b.com/data.json.

    For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. For example, XMLHttpRequest and the Fetch API follow the same-origin policy. This means that a web application using those APIs can only request HTTP resources from the same origin the application was loaded from, unless the response from the other origin includes the right CORS headers.

So if the above (the second paragraph) applies to you, i.e. you're not actually making the CORS/AJAX request from the same origin/domain, then you could:

  1. If you own the domain/website of the calculator web service (dneonline.com).. or have control to its administration, then enable CORS on that site.

  2. Or if your site has a server-side application like PHP or Python, then you can use a server-side script to make the request — example in PHP, you could have calculator.php which makes remote request to the API and then your script makes AJAX request to the calculator.php.

  3. Or you can use a CORS proxy such as https://cors-anywhere.herokuapp.com which I've tried working — check out the demo below.

Demo: Making AJAX request to a non- CORS-enabled resource using https://cors-anywhere.herokuapp.com

$('#btnCallWebService').click(function(event) {
  $('#intA').val(Number($('#intA').val() || 0).toFixed(0) || 0);
  $('#intB').val(Number($('#intB').val() || 0).toFixed(0) || 0);
  if ('0' === $('#intA').val() && '0' === $('#intB').val()) {
    alert('Non-zeros only.. for this demo.');
    return;
  }

  var $btn = $(this), _btn_text = $btn.val();
  $btn.prop('disabled', true).val('Calculating..');
  $('#response').hide();

  var wsUrl = 'http://www.dneonline.com/calculator.asmx';
  var soap12Request = '<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">  <soap12:Body>    <Add xmlns="http://tempuri.org/">      <intA>' + $('#intA').val() + '</intA>      <intB>' + $('#intB').val() + '</intB>    </Add>  </soap12:Body></soap12:Envelope>';

  $.ajax({
    type: 'POST',
    url: 'https://cors-anywhere.herokuapp.com/' + wsUrl,
    contentType: 'application/soap+xml', // can also be text/xml
    dataType: 'xml',
    data: soap12Request,
    success: function(xml){
      var $doc = $(xml);
      $('#answer').html($doc.find('AddResult').text());
      $('#response').show();
    },
    complete: function(){
      $btn.val(_btn_text).prop('disabled', false);
    }
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Enter the numbers:
<input id="intA" type="number" placeholder="No decimals" /> <code>+</code>
<input id="intB" type="number" placeholder="No decimals" />
<input id="btnCallWebService" value="Call web service (SOAP 1.2)" type="button" />
<div id="response" style="display:none">
  The answer is: <b id="answer"></b>
</div>

Upvotes: 2

A. Nadjar
A. Nadjar

Reputation: 2543

Because of Same Origin Policy, it's not possible to have a page on http://www.example.com and make ajax call to http://www.anotherdomain.com.

Solution?

  • enable CORS on the WCF Service
  • Or, create a back-end proxy to consume WCF, and then make ajax call to this

If you cannot move your javascript on the same domain as the web service, the only reliable way to make this work is to build a server side script that will be hosted on the same domain as your javascript code. So you would send an AJAX request to your server-side script which in turn will invoke the remote web service and return the result. The following links show how to create a simple server-side ASP.Net MVC to consume WCF service:

jQuery SOAP offers a jQuery plugin for communicating with a web service using SOAP,assuming that your javascript and web service are on the same domain.

Upvotes: 1

Related Questions