jQuery getJSON 回调不工作 - 即使有有效的 JSON - 似乎使用 "OPTION" 请求而不是 "GET

4 投票
4 回答
6864 浏览
提问于 2025-04-15 13:11

背景是我有一个用Django配置的分布式任务服务器,使用celery来处理任务,这个服务器可以返回正在运行的任务状态,格式是JSON。这个任务服务器的地址是celeryserver.mydomain.com,而我执行jQuery的页面是在www.mydomain.com,所以我应该不需要考虑JSONP,因为请求并不是发往不同的域名,对吧?

从我的服务器日志来看,我看到jQuery每3秒执行一次getJSON调用,这个是正常的(因为有JavaScript的setInterval)。确实它会使用一个OPTION请求,但我用curl确认过,这种请求类型依然能返回JSON数据。

问题是,下面jQuery中的console.log()调用似乎从来没有执行过!在getJSON调用之前的那个是执行了的。没有回调函数正常工作对我来说是个问题,因为我希望通过这种方式来轮询celery任务的状态,并根据任务的状态做不同的事情。

<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>

我用curl确认了我从服务器收到的内容:

$ 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"}}

我觉得那个JSON看起来没问题,JSONlint.com现在也帮我验证过了……我还用-X OPTION模拟了jQuery的查询,结果从服务器返回的数据和用GET请求得到的完全一样(内容类型是application/json等等)。

我盯着这个问题看了很久,非常感谢任何帮助。我是个比较新的jQuery用户,但这看起来应该没有问题,所以我不知道我哪里出错了!

4 个回答

1

正如很多人提到的,子域名也算作独立的域名,所以我遇到了跨域的问题 :)

我通过创建一个小的Django中间件解决了这个问题。这个中间件会检查我的视图返回的内容,如果是JSON格式并且请求中有回调函数,它就会对响应进行一些修改。

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

现在一切都按计划进行,感谢大家!

1

把你的网址改成这样:

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

然后在你的 Django 视图中,结果应该类似于:

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

...其实有很多方法可以实现最后那一行,但基本上就是读取回调参数(你可以随便给它起个名字)

然后把它作为调用你的 JSON 对象返回(jQuery 会自动处理创建回调函数,它会把 '?' 替换成生成的函数)

3

我觉得你遇到了跨子域的问题,sub.domain.tlddomain.ltd 不是同一个东西。

我建议你安装一下 Firebug,看看你的代码在请求开始时是否出现了 权限被拒绝 的错误。如果是这样的话,可以考虑使用 JSONP...

撰写回答