I've been trying to interact with the Amazon DynamoDB via JavaScript using jQuery and an Ajax call but have been unsuccessful. After two days of research I am beginning to thing it may not be possible. I see that they have SDKs available for Java, PHP, and .Net, but nothing for JavaScript yet.
Amazon explains how to send a command to dynamo in this link:
http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/UsingJSON.html#JSONMajorExample
I've been able to do it with the PHP sdk and with node.js (https://github.com/xiepeng/dynamoDB), but no luck with a regular javascript ajax call or xmlHttpRequest call.
I have been able to get a valid aws signature, secret id, and session token, so I have hard coded those into the headers.
Here is my code:
$.ajax({
beforeSend: function(xhr) {
console.log("getting built");
xhr.setRequestHeader('host', 'dynamodb.us-east-1.amazonaws.com');
xhr.setRequestHeader('x-amz-date', 'Fri, 10 Feb 2012 20:44:00 GMT');
xhr.setRequestHeader('date', 'Fri, 10 Feb 2012 20:44:00 GMT');
xhr.setRequestHeader('x-amz-security-token', '**MYSECURITY TOKEN**');
xhr.setRequestHeader('x-amz-target', 'DynamoDB_20111205.PutItem');
xhr.setRequestHeader('content-type', 'application/x-amz-json-1.0');
xhr.setRequestHeader('content-length', 103);
xhr.setRequestHeader('x-amzn-authorization', 'AWS3 AWSAccessKeyId=**MY ACCESS KEY**,Algorithm=HmacSHA256,SignedHeaders=host;x-amz-date;x-amz-security-token;x-amz-target,Signature=**MY SIGNATIURE**=');
},
type: "POST",
url: "http://dynamodb.us-east-1.amazonaws.com",
dataType: "json",
data: '{"TableName":"Sample","Item":{"RecordId":{"S":"white"},"Square":{"S":"teess"},"circle":{"S":"eeerer"}}}',
error: function(XHR,textStatus,errorThrown) {
// alert ("XHR="+XHR+"\ntextStatus="+textStatus+"\nerrorThrown=" + errorThrown);
console.log(XHR);
console.log(textStatus);
console.log(errorThrown);
},
success: function(data) {
console.log("success");
}
});
When I run this I get a 404 Not found error, with the method showing as "OPTIONS" (as opposed to POST or GET)
Not very familiar with AWS Dynamo, but am very familiar with HTTP and XMLHttpRequest and Host is not a header that you can set via xhr. XHR pulls the host info from the url that is being requested. Not sure if $.ajax will ignore you trying to set that header or not, but I would try it without it.
Also, how are you calculating your content length? Your string there is 103 characters, but it is not necessarily 103 bytes (depending on encoding, charset, etc), which is how Content-Length is calculated. I would try it without that header as well.
Let us know how it goes!
UPDATE:
I think is falling victim to the 'Same-Origin Policy' that has been a part of Ajax since Microsoft made that decision for everyone. :-) You're going to have to code some sort of server-side proxy that resides on your domain, and make the Ajax requests to/from that.
Are you familiar with PHP? It looks like AWS has a lib for DynamoDB in PHP.
You are attempting to make a cross-domain request with AJAX. This is not something that necessarily works unless both your application and the service are setup for it. AWS does not currently allow requests via the CORS protocol. The OPTIONS header that you saw is your JavaScript making a pre-flight CORS request to AWS, which is being rejected. You will need to use a server-side proxy (which uses one of the SDKs provided by AWS) to make the actual service calls. Your JavaScript can talk to your proxy via AJAX since it will be hosted on the same domain.
Related
I have a number of JavaScript functions that I am using in Google Sheets to perform various webpage speed tracking and archiving steps.
Would like to leverage the Internet Wayback Archive to store pages when the page score shifts +/- a particular score range.
The challenge that I'm having is that I'm not sure how (if it's possible) to execute a converted curl command from within the Google Sheets script editor interface.
If I understand things correctly, I would need to convert the following curl code:
curl -X POST -H "Content-Type: application/json" -d '{"url": "google.com"}' https://pragma.archivelab.org
to the following format:
$.ajax({
url: "https://pragma.archivelab.org",
type: 'POST',
dataType: 'json',
contentType: 'application/json',
processData: false,
data: '{"url": "google.com"}',
success: function (data) {
alert(JSON.stringify(data));
},
error: function(){
alert("Cannot get data");
}
});
Am I approaching this the correct way? Will this type of call work in the Google Sheets scripting toolset?
The biggest thing that differentiates cURL and Ajax is that AJAX is client side code. Browsers have to follow strict behaviours to prevent malicious behaviours. Ajax is bound to the CORS policy which means that if you are requesting a page from another domain, that domain should explicitly state that your domain (or global domains, or even wildcard for) is allowed to do such thing.
The JSONP protocol is not bound to the CORS. It is done so because it cannot cause harm, and it makes building/using APIs easier. Luckily, the web archive seems to be well supported by mementoweb, who provide an API just like that.
Read more about it here
Send your request to http://timetravel.mementoweb.org/api/json/YYYY<MM|DD|HH|MM|SS>/URI and mementoweb will send you the list of Memento closest to the specified date.
I hope it helps you go forward.
And to answer your question, your request is just fine. Note that the data attribute could be a simple object instead of string, jQuery will handle the rest for you.
Try sending the requests to your own server and having said server do the curl using something like python on php on the server side, that way you can go around the CORS headers nightmare you are in your way to.
I am trying to build a quick demo site that I do not have control over the server I am trying to connect to. Here is the code that I am using to build it with AngularJS. I am running the file through a simple Python HTTP Server and viewing it at localhost:8000.
var retrieveAppliances = function () {
console.log('Attempting to retrieve appliance list.');
var requestUrl = '****';
$http({
method: 'GET',
url: requestUrl,
})
.then(function (response) {
console.log(response);
});
};
retrieveAppliances();
I have read multiple places to try switching the method to JSONP but doing so resulted in a parsing error.
While I have considered trying to build a server.js file and running NodeJS with it, I am unsuccessful in learning the basics of making an AJAX request and proxying that to my app.js.
I will greatly appreciate any help that someone may be able to give me, with clear and easy to follow steps.
If you're running an Ajax call to a different origin (e.g. different host, port or protocol) and the server at that origin does not have support for cross origin requests, then you cannot fix that from your client. There is nothing you can do from the client.
If the server supported JSONP, you could use that, but that also requires specific server support.
The only solutions from a browser web page are:
CORS support on the target server.
JSONP (also requires support on the target server).
Set up your own server that you do have access to (either on your existing page domain or with CORS) and then have that server get the file/data for you and proxy it back to you. You can either write your own proxy or deploy a pre-built proxy.
Find some existing third party proxy service that you can use.
If you're interested in making your own node.js proxy, you can see a simple example here: How to create a simple http proxy in node.js?.
Been running into what appears to be the Same Origin Policy which is causing quite some headache!
To cut to the chase, I am essentially trying to acquire a user's steam64id when only supplied their username.
For example, my username: "Emperor_Jordan" I would go to:
http://steamcommunity.com/id/emperor_jordan?xml=1
And the steamid I need is right at the top. So I figured I would use JQuery Ajax to acquire this and parse out the id I need for later usage (steamapi usage requires the steam64id) as follows. Here is a snippet of the code in question:
$.ajax({
url: "http://steamcommunity.com/id/emperor_jordan/?xml=1",
datatype: "xml",
complete: function()
{
alert(this.url)
},
success: parse
});
function parse(xml)
{
alert("parsing");
_steamID = $(xml).find("steamID64").text();
}
The problem here is while I do get the alert for the completion, I never see "parsing". Ever. It never gets that callback, which leads me to believe I am running into the SOP (same origin policy).
Am I approaching this the wrong way, is there a workaround?
Thanks!
Correct. You are running into the same-origin policy:
XMLHttpRequest cannot load http://steamcommunity.com/id/emperor_jordan/?xml=1. Origin http://fiddle.jshell.net is not allowed by Access-Control-Allow-Origin.
and it looks like Steam does not offer a cross-origin solution like JSONP. That means you're back to the old-but-reliable solution: fetch the data on your server, not in the browser.
Some relevant feedback on the Steam Web API: https://developer.valvesoftware.com/wiki/Steam_Web_API/Feedback#API_Considerations_for_Web_Developers
You need to create a proxy server in Heroku in order to get the data. Cors is restricting us to call the data directly to our browser not server to server interaction. So we need a proxy server to send the requests and receive the data on our behalf. It's working for me.
Thanks in advance.
Ok, so basically.
I inject some javascript code into a web page and it uploads an image on that page to another server.
Now I have it working when I run it on my domain (of course), but I need to post the multipart/form-data request to a PHP file that I do not own.
Since it is a upload and not a simple request to just get data, I cannot use jsonp in the initial call since the response would not be in json.
Using James Padolsey's cross domain script, I am able to do $.get and $.post request across domains, but since I am using $.ajax it does not work.
He uses the Yahoo Query Language to acomplish this
This is basically how I am making the request
$.ajax({
url: 'http://website.com/upload.php',
type: 'POST',
contentType:'multipart/form-data',
data: postData,
success: successCallback,
error : function(XMLHttpRequest, textStatus, errorThrown) {
console.log('Error');
}
});
I want to make it completely JavaScript based to avoid making my server do the request.
So to re-cap, I can get the image bytes and make the request with javascript. But so far I cannot make it cross domain since I am $.ajax to set the content Type to "multipart/form-data".
Is there another way to make the request cross domain with or without the YQL?
Making the request with an iframe will not work since the domain of the iframe would change and I would not have access to the response.
This is a well known and difficult problem for web development, know as the Same Origin Policy
Javascript prevents access to most methods and properties to pages across different origins. The term "origin" is defined using the domain name, application layer protocol, and (in most browsers) port number of the HTML document running the script. Two resources are considered to be of the same origin if and only if all these values are exactly the same.
There are several ways around this.
Create your own proxy
Create a page that simply forwards the request to the other server, and returns its response
or, Use Apache's rules to form a proxy (see above link)
Use someone else's proxy
For GET requests which are typical Use YQL to access yahoo's proxy
For POST requests, if the 3rd party supports Open Data Tables
or, Use some other public proxy
See if the 3rd party conforms to the CORS specification
Cross domain POST query using Cross-Origin Resource Sharing getting no data back
If you are willing to allow a little flash on your page, try flXHR
it claims to implement the exact XHR api and also has a jquery plugin
These are pretty much your only options
I am currently trying to send a POST message which works fine except for the error that there are not correct credentials. However, after I add the credentials header, the message type is changed into OPTIONS and fails. I do not understand how adding a header causes the type to change to OPTIONS. Any help would be appreciated.
ajaxRequest = $j.ajax({
url: url,
type: 'POST',
beforeSend : function(req) {
req.setRequestHeader('Authorization', auth),
}
success: function(data, status) {
console.log("Success!!");
console.log(data);
console.log(status);
},
error: function(xhr, desc, err) {
console.log(xhr);
alert('fail')
console.log("Desc: " + desc + "\nErr:" + err);
}
});
EDIT: just to be more clear, I can literally go in and comment out the setRequestHeader function and it sends the message POST.
The problem you're encountering is because of cross-domain restrictions when using AJAX. When you try to set an authorization header, the browser issues what's known as a pre-flight request to see if the server will accept requests from this domain.
A pre-flight request is typically sent as an OPTIONS request. If the server you're invoking doesn't return an Access-Control-Allow-Origin header that matches your domain, the AJAX request is blocked.
There's more on this here: Cross-Origin Resource Sharing
"User agents can discover via a preflight request whether a cross-origin resource is prepared to accept requests, using a non-simple method, from a given origin."
I've run into the same problem- there are a few possible workarounds depending on your scenario.
If you have any way of setting the above mentioned header on the 3rd party server (some applications/services offer this) then that's probably the easiest way.
There's also a javascript library called EasyXDM that may work for you, but again, it will only be of use if you have access to the 3rd party server to upload a configuration file for this library.
Other options to investigate are PostMessage and Cross Domain Iframe communication. The latter is more of an old-school hack, the former is the recommended approach for newer browsers. It won't work for IE6/7.
The option we will probably end up using is a simple proxy- invoke our own server with the AJAX request, and on the server invoke the 3rd party server. This avoids the cross domain issue entirely, and has other advantages for our scenario.
I guess this is a problem in Internet Explorer. without explicitly telling the request-method (POST|GET) the request header doesn't contain the custom-header in IE, but it works in other browsers.
Yet try to post this in the bugs for jquery. Also try in other browsers.
Edit 1 : I saw this as a bug in jQuery 1.4.x .... I reported a bug report now.
The OPTIONS response happens when the server does not know how to respond to the ajax request.
I've seen it happen often when trying to post to a third-party domain (i.e. cross-site posting)
The OPTIONS method represents a request for information about the communication options available on the request/response chain identified by the Request-URI. This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.
Have you tried:
Having some sort of callback on the url that is being posted to?
Explicitly setting the headers (I'm assuming you're using PHP) on the url that is being posted to?