Call ajax HTTP to API with Sinatra - javascript

I'm calling a service from my api built with sinatra, and I make a simple ajax call as I mention it below:
<script>
$(document).ready(function (){
seeStatus()
});
function seeStatus(){
token = $('#token').val();
$.ajax({
url: '/see/v1/status/' + token,
type: 'GET',
dataType: "script",
complete: function (response) {
var json = $.parseJSON(response.responseText);
if (json.error == 0) {
window.location.href = json.href
}
}
});
}
</script>
made a GET call and the server receives a call OPTIONS
190.141.191.102 - - [08/Mar/2018:12:31:38 +0000] "OPTIONS /see/v1/status/f4dce2eb193674cab37ff36cbaca2eb4c0355165?_=1520512306539 HTTP/1.1" 404 51 0.0133
The code of my service is not executed from the ajax method and I do not understand why? , when I try my service independently with an HTTP client it works correctly What can I do? Any help Thanks

It looks like you're having an issue with CORS (Cross-Origin Resource Sharing). It would be interesting to know where the script requesting the API and where the API itself are located. I guess they're not on the same server.
In a nutshell, CORS is a mechanism that prevents a resource on one domain to freely access a resource on another domain. Your webpage can load resource on its own domain (scripts, stylesheets, fonts, json, etc.) but by default, Javascript HTTP requests (XMLHttpRequest / fetch) use the same-origin policy by default, which means they can only request resources on the same domain.
According to the CORS dedicated page on the MDN, here's the reason for the OPTIONS request you see on the server side:
the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method"
I guess you'll have to configure CORS on your server, or make it so that the HTML file calling the API is located on the same domain as the API itself (which might not be possible).
Since you used the Sinatra tag in this question, I guess your server is written in Sinatra, in that case you can use the britg/sinatra-cross_origin gem to setup CORS rule on your API server.

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.

How to access HTTPS API from HTTP server using AJAX

I am trying to integrate an API request with jQuery but I get a "Mixed Content" error because my website is HTTP:// and the API website is HTTPS://. I dont'want to use an SSL certificate on my site. How I can communicate with the API?
This is the code I use:
jQuery(document).ready(function() {
alert("hello");
jQuery.post('http://example.net/privacy/test.php',function(data) {
alert(JSON.stringify(data));
});
});
and use:
$.getJSON('//www.mindicador.cl/api', function(data) { ... });
Is this possible? Thanks for the help.
You cannot bypass this directly.
You could work around the issue by setting up an HTTP domain that server-side just gets the content of the HTTPS site and returns it, thereby bypassing the HTTPS issues since the new domain's JavaScript would be running from an HTTP domain and so could call the HTTP endpoint.
Or you could proxy the call, by setting up (or using some existing) HTTPS endpoint, and having that endpoint call the HTTP endpoint and return the contents it gets from the HTTP endpoint. That way the JavaScript on the HTTPS domain is only ever talking to HTTPS endpoints.

Cross domain AJAX called with JSONP returns plain JSON

I have encountered a problem with an API I want to use. The API returns plain JSON but its a cross domain AJAX call so I have to use jsonp.
$.ajax({
type: "GET",
url: url + query,
contentType: "application/json",
dataType: "jsonp",
success: function(data){
console.log(data);
}
});
The problem is when I change the dataType to "json" an error occurs:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'X' is therefore not allowed access.
This is because its a cross domain ajax call. But when it is jsonp it says:
Uncaught SyntaxError: Unexpected token :
In other words it does not recognize the json format.
I am using jquery for the ajax call. Any suggestions how to solve this?
Since you dont have access to the server where the API is hosted, you use can a web service utility like CURL to access the API. AJAX calls requires CORS (Cross Origin Resource Sharing) to be enabled on the server where the API is served.
You can call a web service on your local server page via AJAX from where the CURL call will be made and appropriate response returned.
There are several methods of bypassing cross-domain restrictions (CORS, JSONP, Iframe transport, etc.) but all methods have in common that the API server needs to corporate. So if you don’t have privileges on the API server, you cannot come across the cross-domain restrictions.
The only way to make this work would be putting a proxy in front of the API that you can control (the proxy could either live on the same domain or inject the appropriate CORS headers). However, this will affect performance and might also have legal implications.
Regarding JSONP, here’s an excellent explanation of how and why this works:
What is JSONP all about?

Not cross-domain. XMLHttpRequest cannot load localhost:portNo1 . Origin localhost:portNo2 is not allowed by Access-Control-Allow-Origin

I have a server created from BaseHTTPServer.HTTPServer in Python at localhost:portNo1
Client-side is at localhost:portNo2 and at client-side, I am making a jQuery $.ajax POST request like this:
var request = $.ajax({
url: "http://localhost:portNo1",
type: "post",
dataType: 'json',
data: json_data
});
At server side, server gets the data from client and replies with its data.
def do_POST(self):
# Get client data
length = int(self.headers.getheader('content-length'))
data_string = self.rfile.read(length)
print data_string;
# Create response object
jsonObjStr = json.dumps(jsonObj);
self.send_response(200)
self.end_headers()
self.wfile.write(jsonObjStr);
What happens is that server is getting the data I sent, but there is no reply to the client and the callback at the fail event of $.ajax object executes at the client-side(error msg). I debugged and verified there is nothing with jsonObj. But I cannot see what is inside self.wfile object.
At the JS console, I get the following error also (it shows up at the JS console of Google Chrome and it doesn't show up in Firefox JS console):
XMLHttpRequest cannot load localhost:portNo1 . Origin localhost:portNo2 is not allowed by Access-Control-Allow-Origin. client.html:1
The JS console at Google Chrome points to html file, but that didn't make sense for me, either.
I checked the website and it seems that the error is generally caused due to cross-domain requests. However, I am communicating from one localhost port to another.
Well, that's the problem. Cross-origin restrictions do not allow you to communicate across ports without sending a Access-Control-Allow-Origin: * header.
A better solution would be to use Nginx or some other webserver to reverse proxy those two running applications to the same domain and port.

REST request from app works, but not from javascript

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.

Categories

Resources