Question

I am attempting to write a user script that makes a cross domain AJAX request.

I have included jQuery inside my script using @require and everything seems to be working fine up until the point where I try to run jQuery.getJSON.

The API I am accessing supports jsonp, however I keep getting an error stating jsonp123456789 is not defined.

From what I have been able to gather this is due to jQuery writing the jsonp response directly into the head of the page, which then becomes sandboxed. Once that has occured jQuery can no longer access the callback resulting in it being undefined. (I'm not 100% on this being the case, but it seems likely to me).

Is there any way to work around this? It has been suggested I declare the callback function inside unsafeWindow but I'm unsure how to do this and haven't managed to get it to work.

Was it helpful?

Solution

Wouldn't it be nice if jQuery used GM_xmlhttpRequest internally so that you could have all the convenience of the jQuery methods and the cross-site functionality of Greasemonkey? As mahemoff points out, Greasemonkey could let you make the request without relying on JSONP and running into the callback problem you're facing, but you'll have to deal with the JSON contents yourself.

We've written a library that will do just that: the Greasemonkey/jQuery XHR bridge. If you @require that script in your userscript, then all $.get and $.getJSON and $.post, etc. jQuery calls will work cross-site without relying on techniques like JSONP.

So if you use this bridge and simply remove the ?callback=? from your URL, your jQuery code should work without modification. This blog post provides a step-by-step walkthrough. If anyone has any questions, comments, bug reports or suggestions about the bridge plugin, please let me know.

OTHER TIPS

The workaround is to use GM_HttpRequest. You can get away with it, instead of JSONP for cross-domain requests, because unlike the usual XHR, GM_HttpRequest does allow cross-domain calls. You want something like:

  GM_xmlhttpRequest({
     method: "GET",
     url: "http://example.com/path/to/json",
     onload: function(xhr) {
      var data = eval("(" + xhr.responseText + ")");
      // use data ...
    }
  });

Note that this eval's JSON the simplest way. If you want a more secure solution for untrusted JSON, you'll need to include a small JSON-parsing library.

Unfortunately, you also have to wrap a seemingly useless zero-duration setTimeout around the whole thing. I find it easiest to stick the GM_xmlhttpRequest in its own method, then run setTimeout(makeCall, 0);.

You can see a real example here.

As many of you will know, Google Chrome doesn't support any of the handy GM_ functions at the moment.

As such, it is impossible to do cross site AJAX requests due to various sandbox restrictions (even using great tools like James Padolsey's Cross Domain Request Script)

I needed a way for users to know when my Greasemonkey script had been updated in Chrome (since Chrome doesn't do that either...). I came up with a solution which is documented here (and in use in my Lighthouse++ script) and worth a read for those of you wanting to version check your scripts:

http://blog.bandit.co.nz/post/1048347342/version-check-chrome-greasemonkey-script

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top