GET working with Postman, but not with Ajax? - javascript

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.

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.

jQuery AJAX request yielding 405 error despite knowing the method is right

I'm using an API that someone else in my company made, and one of the endpoints he's created accepts GET requests with an access key header provided from another endpoint. I use the following jQuery AJAX to call it:
$.ajax({
type:'GET',
url: 'http://myapi.com',
crossDomain: true,
headers: {
"token": data.AccessKey
}
})
In Chrome, this returns 2 error messages in the console:
OPTIONS http://myapi.com jquery.min.js:4k.cors.a.crossDomain.send jquery.min.js:4n.extend.ajax jquery.min.js:4(anonymous function) (index):69j jquery.min.js:2k.fireWith jquery.min.js:2x jquery.min.js:4(anonymous function) jquery.min.js:4
XMLHttpRequest cannot load http://myapi.com. Invalid HTTP status code 405 (index):1
In Firefox I get a different error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://myapi.com. This can be fixed by moving the resource to the same domain or enabling CORS.
But we enabled CORS on the API server (we were getting that message on Chrome, too, before we did) so I don't know why it's saying that.
I know that this endpoint is expecting a GET request. If I send this request with no headers at all, it returns a 200 status and a response containing the expected "You need a key to access this information". If we try it on hurl.it, the GET request with a valid key as a header returns the expected results.
Because of CORS, it's running the pre-flight OPTIONS request, which I think is what's giving the 405 error, but shouldn't the server accept OPTIONS methods? How do we ensure this method is accepted? Is there something else going on that I'm not catching? CORS is a new concept to me so feel free to ELI5 your answers.

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.

post json stringify response 403 Forbidden

I'm trying to post json data
var details= jQuery("#list").jqGrid('getRowData');
$.post("someurl", { szVoucherNo: VoucherNo, dtmTransaction: Transaction, details: JSON.stringify(details) } );
but then i got 403 forbidden response from server.
Please could you tell me what I did wrong?
TIA
From the client side you can NOT make a request into any other domains (not even the same domains different port like :81) then the host itself. This is the same origin policy.
However there are some workarounds to just proxy such requests, see Q: Make cross-domain ajax JSONP request with jQuery and Q: Ajax cross domain call

jQuery, CORS, JSON (without padding) and authentication issues

I have two domains. I'm trying to access a JSON object from one domain through a page on another. I've read everything I could find regarding this issue, and still can't figure this out.
The domain serving the JSON has the following settings:
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, OPTIONS"
Header set Access-Control-Allow-Headers "origin, authorization, accept"
From my other domain, I'm calling the following:
$.ajax({
type:'get',
beforeSend: function(xhr) {
var auth = // authentication;
xhr.setRequestHeader("Authorization", "Basic " + auth);
}
url:myUrl,
dataType:'json',
error: function(xhr, textStatus, errorThrown) { console.log(textStatus, errorThrown); }
})
I know that 'auth' is initialized properly (logged and checked). However, this does not work. In Firefox's Console, I get
Request URL: ...
Request Method:
OPTIONS
Status Code:
HTTP/1.1 401 Authorization Required
If I get rid of the beforeSend:... part, I see the following
Request Method:
GET
Status Code:
HTTP/1.1 401 Authorization Required
However, the domain serving JSON also can serve JSONP. I don't want to use this, mainly because the application will be running constantly on a dedicated browser, and I'm worried about this issue. More importantly, I would really like to know what is actually wrong with what I am doing. I know that for practical purposes there are various ways to overcome the JSONP memory leak (such as not using jQuery).
At any rate, when I did use JSONP, my code looked like this:
$.ajax({
url:newUrl,
dataType:'jsonp',
jsonp:'jsonp'
}).done(function(d){console.log(d)})
This gets the following
Request Method:
GET
Status Code:
HTTP/1.1 200 OK
after it prompts me with an alert box for a username and password.
Is there a fundamental difference in the way jQuery handles JSONP requests as opposed to JSON requests? And if so, how can I fix this?
Thanks.
Edit: Here's what I did find.
Basically, because I need authentication, the GET request is sending an Authorization header. However, this is not a "simple" header, and so the browser is sending a pre-flight request (the OPTIONS). This preflight request doesn't have any authentication, though, and so the server was rejecting it. The "solution" was to set the server to let OPTIONS request not require authentication, and report an HTTP status of 200 to it.
Reference: http://www.kinvey.com/blog/item/61-kinvey-adds-cross-origin-resource-sharing-cors
mail-archive[.com]/c-user#axis.apache.org/msg00790.html (not allowed to post more links)
Unfortunately, the "solution" is only working on Firefox and not Chrome. Chrome simply shows the request in red, but doesn't give me any more info on why it failed.
Edit 2: Fixed on Chrome: The server I was trying to get data from had a security certificate which was not trusted. The preflight request on Chrome failed because of this. Solution
superuser[.com]/questions/27268/how-do-i-disable-the-warning-chrome-gives-if-a-security-certificate-is-not-trust (not allowed to post more links)
Welp, now that I have enough rep a while later, I might as well answer this question and accept it.
When you attempt to send a GET json request to a server with headers, the browser first sends an OPTION request to make sure that you can access it. Unfortunately, this OPTION request cannot carry with it any authentication. This means that if you want to send a GET with auth, the server must allow an OPTION without auth. Once I did this, things started working.
Some examples available here may illustrate further how access control can be combined with CORS. Specifically the credentialed GET example. Access control requires that the request set the withCredentials flag to true on the XMLHttpRequest, and for the server handling the OPTIONS method to do two things:
Set Access-Control-Allow-Credentials: true
Not use a wildcard * in the Access-Control-Allow-Origin header. This has to be set to the origin exactly according to the MDN docs on HTTP access control (CORS).
Essentially, the thing processing the OPTIONS request needs to send back appropriate response headers so you can make that credentialed request.
In your question you stated that the service you are interacting with is returning Access-Control-Allow-Origin: *, which is not compatible with a credentialed cross-domain request. This needs to return the origin specifically.
The aforementioned MDN Http Access Control (CORS) documentation also links to the Server-Side Access Control documentation outlining how a server would potentially respond to various cross domain requests - including handling a cross domain credentialed POST request that requires you to send back the correct headers in response to the OPTIONS method. You can find that example here.
Why don't you try typing the URL you are fetching the JSON from into your browser and seeing what happens. It sounds like you literally just need to authenticate into this other website to access it.
If your site needs to work in other browsers like IE, you WILL need JSONP, by the way. The security won't allow the cross site request to work. The headers won't change that. I believe you will also need to add a security policy in your headers.

Categories

Resources