Sending HTTP cross-domain request with AJAX - javascript

I'm trying to send a HTTP cross-domain request with PUT method with AJAX.
For that, I am using this:
$.ajax({
url: ipv6Nodo+"/config?param=led",
crossDomain: true,
type: 'PUT',
data: "ls=ON",
success: function(data) {
// Do something with the result
console.log(data);
}
});
I am sniffing on the middle and I am seeing that I am really sending a request with OPTIONS method. That's not the problem, because on the server I can accept PUT or OPTIONS similarly. The problem is that the payload request is empty, there is not ls=ON, how I want it. If I throw this request to the same domain, I can see the payload. What's the problem?
Thanks in advance

There's no payload to the OPTIONS request used with Cross Origin Resource Sharing. It's a "preflight" request to find out whether the server allows CORS from your origin. Once you respond to the OPTIONS request with the correct CORS headers, you'll get the PUT request with the data.
See the link for details, but basically:
Browser sends OPTIONS with CORS request headers.
Server decides whether the request is acceptable from that origin, and if so responds with appropriate CORS response headers.
Browser responds with the actual PUT.
This is transparent to your client-side ajax code (but not your server code).

Related

Cannot 'GET' mLab Data b/c of CORS

I can't execute the 'GET' request with the getTasks() function.
$(document).ready(function(){
getTasks();
});
const apiKey = 'xxxxxxx';
function getTasks(){
$.ajax({
type: 'GET',
url: 'https://api.mlab.com/api/1/databases/taskmanager/collections/tasks?apiKey='+apiKey,
contentType: 'application/json',
xhrFields: {
withCredentials: true
},
success: function(data){
console.log(data);
},
error: function(){
console.log('FAIL')
}
})
}
The error that I get is:
api.mlab.com/api/1/databases/taskmanager/collections/tasks?apiKey=xxxxxxx
Failed to load resource: the server responded with a status of 400
(Bad Request)​
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access. The response
had HTTP status code 400.
I understand that Google-Chrome on Windows is CORS enabled, and will not (by default) allow communication with a different domain. I'm not sure what a preflight request is. Regardless, I tried to implement what I saw from Using CORS - HTML5 Rocks​ (from the CORS from jQuery section), but to no avail.
At a guess, the remote API simply does not respond to pre-flight requests for GET calls (because it shouldn't have to).
Your code is triggering a pre-flight request because it is non-simple. This is due to your adding a Content-type: application/json header. A request Content-type header is used to indicate the request payload format. As it is a GET, there is no payload.
Try this instead...
$.getJSON('https://api.mlab.com/api/1/databases/taskmanager/collections/tasks', {
apiKey: apiKey
}).done(function(data) {
console.log(data)
}).fail(function() {
console.log('FAIL')
})
CORS is there to protect you. If you want some more info on it, wikipedia has a good entry on it.
It appears the issue here is that you're trying to access your mongodb hosted by mlab directly from your web app. As you can see in your code, you're providing credentials/api keys to make that request.
My guess is that mlab's intent of not allowing CORS is to prevent you from doing this. You should never put your private API keys in html to be hosted on a web page, as it's easily accessible by reading source code. Then someone would have direct access to your mongodb.
Instead, you should create a server-side application (node, or... ** Whatever **) that exposes an api you control on the same domain (or a domain you give permission to via CORS).
As far as the "preflight" request, if you look in your chrome debugging tools, you should see an additional request go out with the "OPTIONS" method. This is the request that chrome (and most other http clients) send out first to a server hosted on a different domain. it's looking for the Access-Control-Allow-Origin header to find out whether it's allowed to make the request. Pretty interesting stuff if you ever have some time to dig into it.

Having OPTIONS method instead of POST

I want to post input values in my webservice. I had many errors when I checked, I found that OPTIONS was used not POST
Here's my code:
var req = {
headers: {
'Content-Type':'application/json'
}
}
$http.post(url,req)
.then(
function(response){
},
function(response){
});
It's strange why I had OPTIONS not POST and how can I solve such problem? (I am using AngularJS)
From the access-control-request-method header, you're looking at a CORS preflight request. These happen when you're going across origins, before the actual request is sent. The server may respond with headers to indicate whether the actual request is allowed or not, based on source origin, method, etc.
From the MDN docs, any POST request sending JSON will have a corresponding preflight request:
In particular, a request is preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted.

GET working with Postman, but not with Ajax?

I'm attempting to do a simple GET request from a server hosting some account data. The request requires an Authorization header in order to function correctly. I have performed the GET request and retrieved the data successfully in Postman, but attempting to do so in Javascript via Ajax results in a "Invalid HTTP status code 405" error.
Below is a link to a fiddle and a screenshot of the Postman settings. Thanks.!
$.ajax({
beforeSend: function(xhrObj){
xhrObj.setRequestHeader("Authorization","Bearer tj7LTLycpQC6DRup5BkHUO7uVbYaAZI40");
},
type: "GET",
url: "https://api05.iq.questrade.com/v1/accounts",
success: function(e){
console.log(e)
}
});
http://jsfiddle.net/Ldjbp2j8/1/
POSTMAN SETTINGS
From Chrome's JS console:
Failed to load resource: the server responded with a status of 405 (Method Not Allowed)
Because you are adding an Authorization header, you have made the request complex. This requires the browser to make a preflight OPTIONS request to ask for permission to send the complex request.
The server you are making the request to is responding saying that OPTIONS requests are not allowed to that URL.
You will need to modify the server so that it responds appropriately to the preflight CORS request.
Postman doesn't need to make a preflight request because your browser trusts Postman's code. It doesn't know if it can trust the code it received from JSFiddle (AKA potential evil hacker site) with the data api05.iq.questrade.com (AKA potential online banking or company Intranet site) is willing to share with it.
Look at the console errors:
XMLHttpRequest cannot load https://api05.iq.questrade.com/v1/accounts.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://fiddle.jshell.net' is therefore not allowed access. The response had HTTP status code 405.
This is the CORS issue. Browsers sent OPTIONS aka pre-flight request to the server if the domain doesn't match with the domain of the running code.
And you must add the required headers to the responses as well.
You must modify server to handle that.
You can also use JSONP as an alternative.

Webkit browsers will not allow me to set CORS preflight headers [duplicate]

This question already has answers here:
XMLHttpRequest cannot load XXX No 'Access-Control-Allow-Origin' header
(11 answers)
Closed 4 years ago.
I am trying to create a cross origin GET request using jQuery.ajax(). My server is configured to accept such requests. Chrome will not allow me to send the headers:
Access-Control-Request-Method
Access-Control-Request-Headers
Refused to set unsafe header "Access-Control-Request-Method" <- error
message
Here is my ajax request:
$.ajax({
type:"GET",
headers: {
'Access-Control-Request-Method' : 'GET',
'Access-Control-Request-Headers': 'X-Custom'
},
url: "http://localhost:3000",
success: function(msg) {
console.log(msg);
}
});
I was expecting these headers to cause the browser to create a pre-flight request (OPTIONS) to negotiate with the server. I know that I have accomplished this before. Can someone tell me what I am forgetting?
Thanks a lot!
A PREFLIGHT options request automatically takes place on a cross domain request IF the request is not a simple request. A simple request is typically a GET request. Thus if you make a cross domain GET request there will NOT be a preflight OPTIONS request.
However, if you make a cross domain POST request, the browser will, without you instructing it to do so, make a preflight OPTIONS request first. The purpose of this request is to see whether the server permits cross-domain POST requests from your client's domain / IP.
If your server has the correct "Access-Control" headers in the response, that say, yes this client is permitted to make a cross domain POST request, then the browser will proceed to make the POST request. If your server says NO (because the "Access-Control" headers on your server are wrong) then the browser will respect that and will NOT make the second POST request.
See https://www.html5rocks.com/en/tutorials/cors/#toc-handling-a-not-so-simple-request for more info.
Also, you must make sure your server is set to handle incoming OPTIONS requests.

Jquery Ajax Request Called Twice and the first request does not send token in header

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.

Categories

Resources