Hey everyone, I'm working on a widget for Apple's Dashboard and I've run into a problem while trying to get data from my server using jquery's ajax function. Here's my javascript code:
$.getJSON("http://example.com/getData.php?act=data",function(json) {
$("#devMessage").html(json.message)
if(json.version != version) {
$("#latestVersion").css("color","red")
}
$("#latestVersion").html(json.version)
})
And the server responds with this json:
{"message":"Hello World","version":"1.0"}
For some reason though, when I run this the fields on the widget don't change. From debugging, I've learned that the widget doesn't even make the request to the server, so it makes me think that Apple has some kind of external URL block in place. I know this can't be true though, because many widgets phone home to check for updates.
Does anyone have any ideas as to what could be wrong?
EDIT: Also, this code works perfectly fine in Safari.
As requested by Luca, here's the PHP and Javascript code that's running right now:
PHP:
echo $_GET["callback"].'({"message":"Hello World","version":"1.0"});';
Javascript:
function showBack(event)
{
var front = document.getElementById("front");
var back = document.getElementById("back");
if (window.widget) {
widget.prepareForTransition("ToBack");
}
front.style.display = "none";
back.style.display = "block";
stopTime();
if (window.widget) {
setTimeout('widget.performTransition();', 0);
}
$.getJSON('http://nakedsteve.com/data/the-button.php?callback=?',function(json) {
$("#devMessage").html(json.message)
if(json.version != version) {
$("#latestVersion").css("color","red")
}
$("#latestVersion").html(json.version)
})
}
In Dashcode click Widget Attributes then Allow Network Access make sure that option is checked. I've built something that simply refused to work, and this was the solution.
Cross-domain Ajax requests ( Using the XMLHttpRequest / ActiveX object ) are not allowed in the current standard, as per the W3C spec:
This specification does not include
the following features which are being
considered for a future version of
this specification:
Cross-site XMLHttpRequest;
However there's 1 technique of doing ajax requests cross-domain, JSONP, by including a script tag on the page, and with a little server configuration.
jQuery supports this, but instead of responding on your server with this
{"message":"Hello World","version":"1.0"}
you'll want to respond with this:
myCallback({"message":"Hello World","version":"1.0"});
myCallback must be the value in the "callback" parameter you passed in the $.getJSON() function. So if I was using PHP, this would work:
echo $_GET["callback"].'({"message":"Hello World","version":"1.0"});';
Apple has some kind of external URL block in place.
In your Info.plist you need to have the key AllowNetworkAccess set to true.
<key>allowNetworkAccess</key>
<true/>
Your code works in Safari because it is not constrained in the dashboard sever and it is not standards complient in that it DOES allow cross site AJAX. FF IS standards complient in that it DOES NOT allow cross site ajax.
If you are creating a dashboard widget, why don't you use the XMLHttpRequest Setup function in the code library of DashCode. Apple built these in so you don't need to install 3rd party JS libraries. I'm not sure about JSON support but perhaps starting here will lead you in a better direction.
So another solution is to create your own server side web service where you can control the CORS of, the users web browser can't access another site, but if you wrap that other site in your own web service (on the same domain) then it does not cause an issue.
Interesting that it works in Safari. As far as I know to do x-domain ajax requests you need to use the jsonp dataType.
http://docs.jquery.com/Ajax/jQuery.getJSON
http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/
Basically you need to add callback=? to your query string and jquery will automatically replace it with the correct method eg:
$.getJSON("http://example.com/getData.php?act=data&callback=?",function(){ ... });
EDIT: put the callback=? bit at the end of the query string just to be safe.
Related
I am writing my first WebAPI service, to be called from a pure HTML/javascript application. I am starting visual studio first, then running my app in Safari ( it refuses to run in Chrome, and gives this exact error no matter what I do, but has been fine in Safari until now ).
Based on my other SO reading on this, I've added a header that is Access-Control-Allow-Origin with a value of *.
When I push the button in my web app, it makes an AJAX call and I can step through the debugger to see that it's calling my service fine. When it returns, it always returns an object, and the error in Safari in the console is "XMLHttpRequest cannot load (myurl). Origin file :// is not allowed by Access-Control-Allow-Origin".
Any suggestions for how to get Safari to accept the return value would be greatly appreciated. As I said, it's returning a class, which I expected WebAPI would turn in to a JSON string to return to the browser. I don't know if I'm doing something wrong here, or if something is wrong in Safari. I should mention, although I think it's obvious, I am using MVC4, ergo I am using Safari on Windows, not Mac.
Thanks
How are you currently adding the header? The problem isn't getting safari to accept the return value, your WebAPI is rejecting the request.
Here's an article on how to implement CORS in Web API v1 (MVC4). http://goo.gl/BZkrlf
If you can use MVC5/WebAPI v2, there is an easier way to enable CORS via a NuGet package (see this how-to http://goo.gl/60YkgX)
This is an issue with protocol mismatch. You cannot send a cross domain request to HTTP protocol if the request is originating from the FILE protocol. Try viewing the page using a local webserver so you can preview the page in the browser using HTTP. I have experienced this same issue - it is browser side and not a problem with your service.
You can use Microsoft.AspNet.Cors from nuget and adding
var attr = new EnableCorsAttribute("", "", "GET");
config.EnableCors(attr);
to WebApiConfig.cs
I am trying to get the source page of a webpage on a different domain. I know this is easily done with PHP for example but I would like to do it in Javascript because I am getting results from a page and if I use a server-side language, the original website will block the calls since they come from the same IP. However, if the calls are done on the client side, it is like the user request the results each time (different user, different IP, no original site blocking me). Is there a way to do that (even if not in Javascript but client-side).
To clarify the code I want will be applied to an HTML page so I can get the results, style them, add/delete, etc then display them to the user.
Thank you.
Modern browsers support cross-domain AJAX calls but the target site has to allow them by using special headers in the reply. Apart from that, there is no pure Javascript solution AFAIK.
Could you use an iframe? You wont have direct access to the markup to due to cross-domain restrictions, but you can still display the third-party page to the user...
window.onload = function() {
var i = document.createElement("IFRAME");
i.setAttribute("name", "ID_HERE");
i.setAttribute("id", "ID_HERE");
i.setAttribute("src", "URL_HERE");
i.style.maxHeight = "300px";
i.style.width = "100%";
document.body.appendChild(i);
}
On Windows you can use HTA
An HTA can access anything crossdomain in an iframe for example
I'm creating a widget for people to use on their websites, however to keep the widget future-proof, i want it to be self constructing using an external javascript.
So the widget code i would ask people to put on their websites would be something like:
<div id="my_widget"></div>
<script type="text/javascript" src="http://www.external-domain.com/mywidget.js"></script>
mywidget.js would then use jquery's .load() to populate the #my_widget div with an iframe.
Problem is this doesn't work....
what do i need to do?
(note i dont want to have the iframe in the code i give to my customers)
It depends on what url you are specifying in the load function. If this url is not hosted on the same domain that executes the page containing this script won't work due to same origin policy restriction. One possible workaround to make cross domain ajax calls is to use JSON-P if you have control over the server side script which is used in the load function.
Here's the idea behind JSON-P:
You provide a server side script hosted on Domain A which will return JSONP formatted response. Domain A is your domain for which you have full control.
This server side script could be called from Domain B using AJAX.
Let's suppose that http://domainA.com/myscript?jsoncallback=foo returns the following response:
foo({ result: '<strong>Hello World</strong>' });
Now inside mywidget.js you could call this script:
$.getJSON('http://domainA.com/myscript?jsoncallback=?', function(data) {
$('#my_widget').html(data.result);
});
All that is left is to tell the users include mywidget.js script and provide a placeholder with id="my_widget" to host the results (you could even generate this placeholder in the success callback).
Remark: When using JSONP you are limited to GET requests only. This means that there's a limit in the size of the request you can send.
You have total control of their page since you're executing your code on their site.
You can create iframes document.createElement("iframe"), inject it anywhere on the page document.getElementById("my_widget").appendChild(iframe) and do whatever else you feel like.
One thing to be careful with this is to not clutter their namespaces... avoid any usual namespace and make up your own (__my_widget or whatever else is weird). And try to keep the namespaces counts as low as 1, or even none if possible.
Don't use load, use an iframe if you're just trying to load html from your site.
I have looked everywhere and surprisingly can't find a good solution to this! I've got the following code that is supposed to read a text file and display it's contents. But it's not reading, for some reason. Am I doing something wrong?
FTR, I can't use PHP for this. It's gotta be Javascript.
var txtFile = new XMLHttpRequest();
txtFile.open("GET", "http://www.mysite.com/todaysTrivia.txt", true);
txtFile.send(null);
txtFile.onreadystatechange = function() {
if (txtFile.readyState == 4) { // Makes sure the document is ready to parse.
alert(txtFile.responseText+" - "+txtFile.status);
//if (txtFile.status === 200) { // Makes sure it's found the file.
var doc = document.getElementById("Trivia-Widget");
if (doc) {
doc.innerHTML = txtFile.responseText ;
}
//}
}
txtFile.send(null);
}
Any good ideas what I'm doing wrong? It just keeps givimg me a zero status.
EDIT: I guess it would be a good idea to explain why I need this code. It's basically a widget that other folks can put on their own websites that grabs a line of text from my website and displays it on theirs. The problem is that it really can't be server-side since I've got zero control over everyone else's sites that use this.
If this is cross domain, you won't be able to do this with an xmlhttprequest due to the same origin policy.
This exmaple contains jQuery code.
var text;
$.get( "proxy.php", function(data) {
text = data.responseText;
});
Then in proxy.php:
<?php
header('Content-type: application/xml');
$daurl = 'http://www.mysite.com/todaysTrivia.txt';
$handle = fopen($daurl, "r");
if ($handle) {
while (!feof($handle)) {
$buffer = fgets($handle, 4096);
echo $buffer;
}
fclose($handle);
}
Example taken from here:
http://jquery-howto.blogspot.com/2009/04/cross-domain-ajax-querying-with-jquery.html
As explained before, xmlhttp is designed for forbid cross domain requests for security issues. But nothing prevents you from doing this on your server in PHP.
Another example can be found here: http://usejquery.com/posts/9/the-jquery-cross-domain-ajax-guide
Your problem could be with the fact that you can only request XML data from the same domain via Javascript. This is the biggest issue with AJAX calls - if the text file is on another server, you can't get it via AJAX. If it's on the same server, make your request using a relative URL (no http://).
EDIT
Now that I know what you're trying to accomplish ... my recommendation would be to use an iFrame. Build the system on your server using server-side code and allow remote sites to embed an iFrame to display the output on their own sites. NetworkedBlogs uses this for displaying Facebook features on remote sites. iGoogle uses it extensively with their various Apps and Gadgets. It's a fairly tried-and-true method.
The advantage of using an iFrame is that you'll still have control over most of the content of the widget, but you can give end-users control over the styling (just have your iFrame application accept arguments via query variables to change colors, positions, and sizes).
Assuming the AJAX stuff is right (which I haven't confirmed): You say you can't use PHP for this - if you just mean you need it to use javascript asynchronously but can still use server code in some places, what about using PHP (or any server-side language) to do the actual work and return it to the page through AJAX/javascript - this would solve the problem Alex brings up.
So instead of getting from mysite.com/something.txt from javascript, get it from SomeAjaxHelper.php (or aspx or whatever).
For cross domain, you would have to use dynamic script tags to fetch data asynchronously. The todaysTrivia file would be a .js file that stores the data as JSON. Google for "dynamic script tags cross domain" if you want to use this technique.
I understand (I think) that XmlHttpRequest objects adhere to the "same-domain" policy. However, I want to create a simple (POC) local html file that downloads XML from a web server and does something with it (let's start with a simple "alert()").
Is it possible at all? Do I need a special Firefox config option?
The server from which I'm trying to download is not under my control (it's actually a Google API).
My simple attempt is the code from Mozilla's "Using XMLHttpRequest" page. It returns an error I don't really understand from the "send" method.
Disclaimer: I'm mainly a C/C++ developer - never done any serious JS programming, never tried using these APIs.
XMLHttpRequest actually adheres to a much stricter implementation of the same domain policy: while you can set the document.domain property to allow JavaScript served from two sub-domains to talk with each other, you can't do that with XMLHttpRequestObject. In your case, going to a completely different domain, you couldn't do that with JavaScript either.
There are a couple of options. First, you can use a reverse proxy to make it appear that the external site is a sub-domain of your site. Take a look at Apache's mod_proxy, in particular ProxyPassReverse
Another alternative is to return data as a JSON object: <script src="foo"> can retrieve whatever data it wants from wherever it wants. Downside of this is that it's not (easily) repeatable (as in multiple requests from same page).
I also recommend that you Google for "google mashups". Most of these live on the "googlemashops.com" domain, which makes implementation a lot easier. A few live outside that domain, and may give you some ideas.
Edit: rather than use the XMLHttpRequest object directly, I recommend going through a third-party library such as prototype.js
If the XML that you're trying to retrieve is returned by one of Google's JS APIs, then there's no need for XmlHttpRequest(since that can only be used on the same domain as your page anway).
So in the case of using a Google API, such as the Maps one, usually begin by adding a reference to their common API somewhere on your page:
<script type="text/javascript" src="http://www.google.com/jsapi?key=your_google_api_key"></script>
Then add a reference to the specific API(s) you plan to use to your page:
<script type="text/javascript">google.load("maps", "2");</script>
Now you can call the various functions provided by that API:
<script type="text/javascript">
function initialize() {
var map = new google.maps.Map2(document.getElementById("map"));
map.setCenter(new google.maps.LatLng(41.86, 87.68), 13);
}
google.setOnLoadCallback(initialize);
</script>
No XmlHttpRequest required :)
You can use JSONP to do this. I do it here using jQuery and PHP. Basically I use the PHP proxy to wrap the JSON reply so jQuery can handle it. It's under BSD.
Alternatively try using IE8. If you are running from disk and not a website IE8 will ignore all normal domain restrictions and get the data you want.
With jQuery (and presumably XHR, but I try not to use it directly) you can happily do cross-domain requests, provided that you do not specify unusual headers or non-GET methods. If you do want to use these, you must have control of the server to enable OPTIONS requests.
See https://developer.mozilla.org/En/HTTP_access_control for details.