3

一直在尝试创建一个简单的 JSONP 调用,但它并不总是有效,我不知道为什么。这是代码:

服务器端(http://server/server.php):

<?php
    $res = json_encode("It works!");

    if(isset($_GET['callback']) === TRUE) {
        header('Content-Type: text/javascript;');
        header('Access-Control-Allow-Origin: http://client');
        header('Access-Control-Max-Age: 3628800');
        header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
        echo $_GET['callback']."(".$res.");";
    } else {
        echo $res;
    }
?>

客户端(http://client/client.html):

<html>
    <head><title>JSONP</title></head>
    <body>
        <h1>JSONP Experiment</h1>
        <script src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script>
            function process(data) {
                $('#result').text(data);
            }

            $.getJSON(
                'http://server/server.php?callback=?',
                {'callback': 'process'}
            );

        </script>
        <p id="result"></p>

    </body>
</html>

此代码有效并显示“它有效!” 在我的

堵塞。

  • 为什么当我不使用{'callback': 'process'}并将 ?callback=process 直接放入 $.getJSON() URL 时它不起作用?

  • <script src="http://server/server.php?callback=process"></script>如果我使用而不是 $.getJSON() 调用,为什么它不起作用?

两个不工作的案例实际上都返回process("It works");了,但没有执行,为什么?

谢谢

4

1 回答 1

5

这是两个不同的问题,有不同的答案


$.getJSON()当您使用并将回调的名称按字面意思放在 URL 中时它不起作用的原因是因为 jQuery 的工作方式。

首先让我们看看$.getJSON()如果你没有在设置对象中传递任何明确指示它的选项,jQuery 是如何检测到你的调用需要 JSONP 的——它使用这个正则表达式:

/(=)\?(?=&|$)|\?\?/

=?在查询字符串或仅由单个组成的查询字符串中显式查找?- 本质上,检测 URL 将返回 JSONP 需要问号。

没有它,jQuery 会使用 XHR 发出 Ajax 请求,并且服务器会返回正确的数据。接下来会发生什么取决于同源策略。如果像您显示的代码一样,服务器通过Access-Control-*标头指示允许请求,则数据将可以访问,就像通过对客户端原始服务器的 Ajax 请求一样。如果这些标头不存在,则客户端代码将无法访问返回的数据。

但是,至关重要的是,因为它只是发出一个标准的 Ajax 请求并且没有<script>向 DOM 添加元素,这意味着响应文本永远不会被评估为 Javascript 代码——这是 JSONP 机制中至关重要的最后一步。


第二个版本回答起来有点棘手,并且知道所提供信息的答案是正确的,但是对于您在上面显示的 HTML 布局,我有理由相信这是原因:您的 HTML 元素的定义顺序错误。

在页面加载时处理 DOM 时,处理会在每个<script>元素处暂停,同时同步加载和处理相关的 Javascript。这是为了确保所有 Javascript 都按预期的顺序执行,并且任何对以特定位置方式直接修改 DOM 的事物的调用——例如document.write()(你不应该使用,以防你不知道)——是正确地兑现了。

这样做的结果是,如果您将<script>元素放在 DOM中的标记之前<p id="result">,则结果标记实际上并不存在于process()调用函数的位置。而且因为您使用了 jQuery 选择器而不是document.getElementById(),它会吞下如果您尝试直接修改它会导致的错误。

这就是许多 Javascript 开发人员(包括我自己)现在会告诉您应该将<script>标签作为最后一个元素放在<body>.加载和处理所有页面资源的时间,它允许浏览器更快地呈现页面。这样做也消除了使用$(document).ready()/DOMContentLoaded事件之类的东西来延迟执行的需要(顺便说一下,这也可以解决这个问题,但方式有点混乱)。

于 2013-08-01T11:34:55.253 回答