I am trying to set up a client script to make an ajax call to a web service on a different domain, to make things more complicated the web service is HTTPS. The service is MVC4 WebApi (REST). The client script is also running from a HTTPS domain. I am getting an "Access is denied" error when I try to make the call. For example, I have a script running at https://domain_a.com/clientpage/script.js and making a call to https://domain_b.com/serviceapi/method/, the ajax error callback reports the Access is Denied error. I took this exact scenario and tested without SSL in the mix, so http to http, and then the ajax call works fine, I also set $.support.cors = true, and also tried crossDomain: true in the ajax options. Is this supposed to work with https, am I missing something, or will this simply not work? Any suggestions?
Here is a sample of my ajax call:
$.support.cors = true;
$.ajax({
url: requestURL,
crossDomain: true,
type: "GET",
headers: { "Authentication": "user#domain.com:" + hashcode },
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
alert("call succeeded");
},
error: function (response) {
alert("call failed");
}
});
jQuery version: 1.10.2
browser: IE9 (hoping this can work with multiple browsers: chrome, firefox, safari)
web service: MVC4 WebAPI .NET 4.5
UPDATE:
I did some more testing and ruled out the web service as the issue, it appears to be an issue with the underlying xmlhttprequest object or the browser. I ran fiddler while testing the https to https scenario (fiddler is set to decrypt https traffic and I tested this) and there is no traffic whatsoever when I try to make the ajax call and it fails. That leads me to believe its the browser. Here's the list of scenarios I tested and the result:
http to http, same domains: success
http to http, different domains: success
https to https, same domains: success
https to https, different domains: fails. <<-- I would expect this to be one of the most common scenarios for web service usage, some ISV makes a service available to customers who call it from a different domain, and they want to use SSL.
Sometimes when developing in a development environment, most companies don't dish out the money for a ssl cert and use a self signed cert which can cause the browser to throw up the big red screen that says warning and you have to continue. In Chrome i know when you do this kind of stuff using an iframe, it crashes the iframe window unless i accept the cert during that session.
With that said, are you sure that domain_b.com has a valid ssl cert? if not have you accepted the SSL cert in your browser session? You can test this by manually copying the URL from the ajax call, paste it in the window and visit it. Once you accept the cert, it should start working.
You may see an image like this:
If so, click Proceed anyway
I didn't directly solve the issue of calling cross-domain on https, however I did come up with a workaround that was acceptable in my situation: Instead of attempting to call cross-domain directly from the client I built a web service that sits between the client and server on the other domain. The web service is on the same domain as the client and so the client can call this service without any trouble. The web service then uses standard HTTP communications to send requests to the remote server and accept responses, the responses are then returned back to the client. Basically the local web service acts like a sort of proxy between the clients and remote server.
Related
I have a simple app that I'm writing in a single web page, that is only ever going to live on a network share. It is meant to grab data from a webservice and present it nicely. I'm deving it on my local PC in Firefox 26.0. I'm using jQuery to help with this. The data coming back is XML (from jira, fwiw).
The calls are being made, and the response is being received by the server. The FF web dev tool tells me the response is a 200 OK. However, the response body is empty. The error callback gets called every time.
The code:
$.ajax({
type: "GET",
url: "http://myjiraserver?lalalalala",
dataType: "xml",
crossDomain: true,
processData : false,
success: function(response) {
var result = "";
$(response).find("item type").map( function() {
if (this.text == "Risk") {
result += "<p>" + this.text + "</p>";
}
} );
$("#test").html(result);
},
error: function(xhr, status, error) {
alert('Error: status = ' + xhr.responseText + " " + error + " " + status );
}
});
I run the same code in IE8 and it gets the response, which jQuery successfully parses. (I'd dev it in IE8 but I need the dev tools that FF has; and chrome doesn't work on this PC - another story)
Given I know the webservice is working, and the js works in IE, my working theory is that this is some sort of cross domain issue, but I really have no idea!
Any idea as to what the issue might be? Suggestions for how to work around it?
The fact that it's working in IE is because JQuery uses activex rather than XmlHttpRequest in ie for ajax requests. Standard XHR requests don't allow for local files to access remote servers (or vice versa).
Even if your code ran from a web server, this wouldn't work in firefox or chrome. I see you're using the 'crossDomain' parameter, but you've misinterpreted it. From the jquery docs:
crossDomain (default: false for same-domain requests, true for cross-domain requests)
Type: Boolean
If you wish to force a crossDomain request (such as JSONP) on the same domain, set the value of crossDomain to true. This allows, for example, server-side redirection to another domain. (version added: 1.5)
So you set crossDomain to true if you're using jsonp, but you're using a local server-side redirect to the cross-domain resource.
Normally to access a cross-domain api via javascript, you would either use JSONP, or you would use CORS (Cross Origin Resource Sharing), unfortunately neither of which is supported by jira. (This article states Jira has effectively killed javascript API access). A third option is, you could set up a middle-man server which fetches the data and returns it to your local page. That middle-man page would have to have CORS enabled. Here's an example of how to enable CORS headers in PHP: CORS with php headers
Your javascript would then have to refer to your middleman page and pass it the api page you want to access:
$.ajax({
type: "GET",
url: "http://middeman.com?page="+escape( 'http://myjiraserver?lalalalala' )+"&method=GET"
...
);
I'm building an app that has to get and set data at a remote web service through requests. When I use the jQuery GET request it works fine, I can request data from the service without any problems, but when I use PUT I get some erros:
OPTIONS http://myurl.com 501 (Unsupported method
('OPTIONS'))
OPTIONS http://myurl.com Origin null is not allowed by Access-Control-Allow-Origin.
I've tried almost anything to get this to work, but it won't work. I've download a chrome app called REST Console, which can make custom REST requests. The strange thing is that I can interact with my server over that app but not through my javascript!
This is the javascript:
$.ajax({
url: 'http://myurl.com',
type: 'PUT',
data: '<time>16:00</time>',
success: function(data) { alert(data); }
});
Could anybody tell me what is going on here?
First ensure you're serving the page that runs the script from a web server, not directly from the file system.
I'm guessing your service at http://myurl.com is at a different host name to the host name your page is being served from? For it to work in this case you need to implement HTTP headers to support Cross Origin Resource Sharing.
Your service at http://myurl.com needs to handle an HTTP OPTIONS request, the response to which should be a set of HTTP headers (with no content) as follows:
Access-Control-Allow-Origin: http://url-of-page-with-javascript/
Optionally you can also specify Access-Control-Allow-Credentials, Access-Control-Allow-Headers and Access-Control-Allow-Methods. See the full specification here.
You'll also need to add the same headers with the same values when your server responds to the PUT request - obviously the content will also be included with this response.
I am using ajax to call a WCF REST based service.
The ajax method is called before the page gets loaded.
I wish to send a "Token" in the header of ajax request. In fiddler this is what I see:
1.)A request to the service without the token in the header.(AJAX Call failure)
2.)A request to the same service with the token in the header.(AJAX Call Passed)
After that everything works fine on chrome and safari. But there is only one service call on IE 10 and Mozilla. As a result the service call fails in IE 10 and Mozilla since there is no token in the header of the request.
This is the method that I call:
function callservice (method, serviceUrl, params, successHandler, errorHandler) {
$.ajax({
crossDomain: true,
type: method,
url: serviceUrl,
beforeSend: function (XMLHttpRequest) { XMLHttpRequest.setRequestHeader("Authorization", Token); },
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successHandler,
error: errorHandler
});
function photos(data) {
alert(data);
console.log(data);
};
}
I control both the Web Service and the application(Which calls this Web Service). This problem does not arise when both the application and web service are hosted on the local host.In that case there is only one successful service call. But there are two AJAX calls when there is a cross domain call.
My question is why doesn't the AJAX request send the token in the first attempt?
And why does the token get sent only in the second AJAX call?
Any kind of help will be greatly appreciated.
The problem was with CORS.Earlier,browsers did not allow ajax requests to be made to a domain which is different than that of a client as it was considered as a security threat.Modern browser's can make cross domain ajax request's as long as the server co-operates with the client.So this is what actually happens when there is a cross domain request from a browser:
1.)First the browser sends 'Preflight' request to the service to gather authorization information(which was a request with the header method as 'OPTIONS' in my case) from the WCF service. In return the Web Service sends Access Control Allow Origin as a part of its response header.And the error being displayed on fiddler as a result of this request was a HTTP 500 error.This AJAX request has nothing in the data field since it was just a way to find the authorization details of the WCF service.
2.)Chrome and Safari then made a second request to the Web Service now that they have the authorization details of the service.Whereas Firefox and IE did not prefer to make a second ajax request to the service since there was an HTTP 500 error for the pre-flight request. Hence both Chrome and Safari were able to communicate with the service.
So the solution was to modify the response from the WCF service in case there is a 'Preflight request' made to it.I modified the response sent by the service in case there is a 'Preflight request' to send an HTTP 200 OK Response. This allowed browsers like IE and Mozilla to send the actual request after the preflight request.
Here is one of the sources which I referred:
http://www.bennadel.com/blog/2327-Cross-Origin-Resource-Sharing-CORS-AJAX-Requests-Between-jQuery-And-Node-js.htm
Hope this helps people facing the same problem.
Cross domain call is under the same origin policy. You can not make the calls by default. You need to use CORS or JSONP or a proxy.
XMLHttpRequest: Unless they changed it, With MS Explorer you'll need to use ActiveXObject("Microsoft.XMLHTTP"). For my ajax call made in plain JS, i use this line to create the object according tyo the browser:
if (window.XMLHttpRequest){
//for most BRowsers
r = new XMLHttpRequest();
} else{
//for Explorer
r = new ActiveXObject("Microsoft.XMLHTTP");
}
then apply your beforesend to the object created here (r) in my case. I truely believe this is your issue with EI. But not tested.
Hi
I have a website html embadded with java script, the website uploaded into apache tomcat, the website suppose to contact another server and retrieve json data back, this is not happening the packet tracing shows the tcp handshake is terminated by a FIN state the packet send before the FIN state has a checksum incorrect, I'm not sure how to troubleshoot this ? do you think the checksum incorrect is terminating the handshake ? and hwo to avoide that ? the following is my ajax jquery code
note: both apache server and the other server are in the same domain.
Thank in advance
LS
$(document).ready( function() {
var home_add='http://myhome.net:3300/gateway';
$('#handshake').click(function(){
alert(" sending json data");
$.ajax({ /* start ajax function to send data */
url:home_add,
type:'POST',
datatype:'json',
contanttype:'text/json',
async: false,
error:function(){ alert("handshake didn't go through")}, /* call disconnect function */
data:{
"supportedConnectionTypes": "long-polling",
"channel": "/meta/handshake",
"version": "1:0"
},
success:function(data){
$("p").append(data+"<br/>");
alert("sucessful handshake")
}
})
})
})
You seem to be misunderstanding the same-origin policy. The same-origin policy used by XMLHttpRequest, the basis for jQuery's AJAX functionality, is:
The two hostnames must be exactly the same (not just part of a higher level domain).Example: A web page from careers.stackoverflow.com can access the same domain but not beta.careers.stackoverflow.com, stackoverflow.com, or foo.stackoverflow.com.
The two protocols must be exactly the same (http/https).Example: A web page from http://stackoverflow.com cannot access https://stackoverflow.com and vice-versa.
The two port numbers must be exactly the same (except in Internet Explorer).Example: A web page from http://stackoverflow.com cannot access http://stackoverflow.com:8080 and vice-versa in Firefox, Chrome, Safari, or Opera.
You will have to do one of these:
Use the Access-Control-Allow-Origin HTTP header in AJAX responses, with the obvious disadvantage of excluding browsers such as IE and older versions of the others that do not support it
Use JSONP, which is supported by jQuery though not for synchronous requests (which you should avoid anyway because they can hang the browser)
Proxy HTTP requests from the server your web page is served on to the other server
I have some local html/js files with which I'd like to invoke some remote servers via https and eventually use Basic Authentication for the request.
I am encountering two problems. First is that if I don't specify 'jsonp' for the dataType, jQuery.ajax() request returns the error:
Access to restricted URI denied code:
1012
Are my requests considered cross-domain because my main work file is stored locally, but retrieving data from a server elsewhere?
So fine, I update the call so it now looks like:
$.ajax({
url: myServerUrl,
type: "GET",
dataType: "jsonp", // considered a cross domain Ajax request if not specified
username: myUsername,
password: myPassword,
success: function(result)
{
// success handling
},
error: function(req, status, errThrown){
// error handling
}
})
Because I need to use Basic Authentication, I'm passing in the username/password but if I monitor the request, I don't see it being set and additionally, the server sends an error response since it doesn't have the expected info.
Additionally, because I have jsonp set, beforeSend won't get invoked.
How do I pass along the credentials using Basic Authentication for this request?
The short version is you can't do this. Your suspicions are correct, because you're local and these files are remote, you can't access them, you're being blocked by the same-origin policy. The work-around for that is JSONP, but that really doesn't seem to apply to your situation...
JSONP works differently, it's a GET request via a <script> tag include to get the file, so you're not sending special headers or anything.
You'll need to proxy the request through the server you're on (the domain of where this script is running) or another proxy option, but going from the client to another domain is blocked, mainly for security reasons.
Try doing http://user:password#restservice. This mimics a basic-auth request.
I think you'll have to add a server proxy of some sort. JSONP is just a particular way to use a script tag. Thus, it doesn't allow setting arbitrary headers. And of course, you can't do a cross-origin XHR.