views:

2628

answers:

4

Hello,

The background is that I've got a celery distributed job server configured with a Django view that returns the status of a running job in JSON. The job server is located at celeryserver.mydomain.com and the page I'm executing the jQuery from is www.mydomain.com so I shouldn't need to consider JSONP for this should I, as the requests aren't being made to different domains?

Watching my server logs I see that jQuery is executing the getJSON call every 3 seconds as it should (with the Javascript setInterval). It does seem to use an OPTION request, but I've confirmed using curl that the JSON is still returned for these request types.

The issue is that the console.log() Firebug call in the jQuery below doesn't ever seem to run! The one before the getJSON call does. Not having a callback work is a problem for me because I was hoping to poll for a celery job status in this manner and do various things based on the status of the job.

<script type="text/javascript">
    var job_id = 'a8f25420-1faf-4084-bf45-fe3f82200ccb';

    // wait for the DOM to be loaded then start polling for conversion status
    $(document).ready(function() {
        var getConvertStatus = function(){
            console.log('getting some status');
            $.getJSON("https://celeryserver.mydomain.com/done/" + job_id,
                function(data){
                    console.log('callback works');
                });
        }
        setInterval(getConvertStatus, 3000);
    });
</script>

I've used curl to make sure of what I'm receiving from the server:

$ curl -D - -k -X GET https://celeryserver.mydomain.com/done/a8f25420-1faf-4084-bf45-fe3f82200ccb
HTTP/1.1 200 OK
Server: nginx/0.6.35
Date: Mon, 27 Jul 2009 06:08:42 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: close

{"task": {"executed": true, "id": "a8f25420-1faf-4084-bf45-fe3f82200ccb"}}

That JSON looks fine to me and JSONlint.com validates it for me right now... I also simulated the jQuery query with -X OPTION and got exactly the same data back from the server as with a GET (content-type of application/json etc.)

I've been staring at this for ages now, any help greatly appreciated. I'm a pretty new jQuery user but this seems like it should be pretty problem-free so I have no idea what I'm doing wrong!

A: 

Are you fetching the JSON from another domain? If so, you're most likely running into cross-domain issues. You'll need to use JSONP. jQuery does this automatically, but the server needs to know that.

See:

http://www.ibm.com/developerworks/library/wa-aj-jsonp1/

thedz
Nope, same domain; page with jQuery is served from www.mydomain.com and the getJSON call is retrieving JSON from xyz.mydomain.com
markhellewell
That counts as separate domain -- cross domain policies come into play even on different subdomains.
thedz
+3  A: 

I think you have a cross-subdomain issue, sub.domain.tld and domain.ltd are not the same.

I recommend you to install Firebug and check if your code is throwing an Permission denied Exception when the request starts, if it's the case, go for JSONP...

CMS
+1  A: 

change your url to something like:

"https://celeryserver.mydomain.com/done/" + job_id + "?callback=?"

and then on your django view result should be something to the effect of:

'{callback}({json})'.format(callback=request.GET['callback'], json=MyJSON)

...there are probably plenty of ways of doing that last line, but basically read in the callback parameter (or name it whatever you want)

and then return it as calling your json object (jQuery takes care of creating a callback function (it replaces '?' with the generated function))

Terence Honles
+1  A: 

As several people stated, sub-domains count as domains and I had a cross-domain issue :)

I solved it by creating a little piece of Django Middleware that changes the response from my views if they're returning JSON and the request had a callback attached.

class JSONPMiddleware:
    def process_response(self, request, response):
        ctype = response.get('content-type', None)
        cback = request.GET.get('callback', None)

        if ctype == 'application/json' and cback:
            jsonp = '{callback}({json})'.format(callback=cback, json=response.content)
            return HttpResponse(content=jsonp, mimetype='application/javascript')
        return response

All is now working as planned. Thanks!

markhellewell