Reputation: 12327
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!
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
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
Reputation: 15620
Where am I wrong?
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.
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
usesXMLHttpRequest
to make a request forhttp://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:
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.
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
.
Or you can use a CORS proxy such as https://cors-anywhere.herokuapp.com which I've tried working — check out the demo below.
$('#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
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?
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